跳转至

AI

AI Agent 层级

  • Prompt
  • Structed Output
  • Tool Calling
  • 基本模型能力
  • RAG
  • Chunk
  • Embedding
  • Retrieval
  • Rerank
  • Context Management
  • Workflow
  • LangGraph
  • State Machine
  • Multi-Agent
  • Routing
  • Planning
  • Tool Selection
  • MCP
  • API
  • Database
  • Kafka
  • Python
  • Browser
  • Internal Service
  • Guardrail
  • Permission
  • Sandbox
  • Human-in-the-loop
  • Retry
  • Fallback
  • Validation
  • Rollback
  • Evaluation
  • Trace
  • Bad Case
  • A/B Test
  • Latency
  • Cost
  • Success Rate
  • Business Metric

Tool Call / Function Calling

LLM 擅长语义理解与意图识别,但存在知识时效截止、缺乏确定性计算能力、无法直接操作外部系统等局限。

核心机制:LLM 本身并不直接执行外部代码,而是根据工具定义(Schema)判断调用时机并生成结构化参数(JSON),由宿主程序实际执行工具,再将执行结果(Observation)返回给 LLM 组织最终回答。常见工具如:实时搜索、计算器、数据库查询、业务 API 等。

RAG

RAG 的完整流程可分为离线索引与在线推理两个阶段:

离线索引:解析、清洗文档 → 分块(Chunking) → 通过 Embedding 模型向量化 → 存入向量数据库。

在线推理:

  1. 检索 (Retrieval):根据用户问题,从向量数据库中检索语义最相关的 top-K 候选文档片段。
  2. 增强 (Augmentation):将检索到的文档片段与用户问题组合,构建扩展上下文(Context),作为 Prompt 一并送入 LLM。
  3. 生成 (Generation):LLM 基于扩展上下文进行回答,确保答案的准确性和可追溯性。

向量数据库

产品 特点 适用场景
FAISS (Meta) 单机库,非完整数据库;极致性能研究向 原型、离线实验、嵌入现有服务
Milvus 云原生、分布式、可扩展至百亿级 大规模生产、需要分区与多副本
Pinecone 全托管 SaaS,零运维 快速上线、无运维团队
Chroma 轻量、易上手 原型、小项目
Weaviate GraphQL API、内置模块 需要图式查询与生态集成
Qdrant Rust 实现、过滤丰富、性能强 自托管生产、复杂过滤

ANN(近似最邻近)算法:

  • HNSW(分层导航小世界图):图索引,查询延迟低,内存占用偏高;高召回常用
  • IVF(倒排文件):聚类划分桶,查询只搜索部分桶;需训练,适合大规模
  • PQ(乘积量化):向量压缩,节省内存、加速距离计算;有损,精度略降

图数据库与知识图谱

在 RAG 中,纯向量检索仅关注局部语义相似度,难以捕捉实体间的结构化关联——例如"某人创立了某公司"或"某项目依赖某技术"这类显式关系。图数据库通过构建知识图谱(Knowledge Graph),将离散的文档信息组织为结构化的实体-关系网络,从而帮助 Agent 实现跨文档关联与多跳关系推理。

Neo4j

Neo4j 是目前最主流的原生图数据库,采用 LPG(Labeled Property Graph,标签属性图)模型,其核心由四个基本元素构成:

  1. 节点 (Node):表示实体或概念(如 Person、Company、Project)。
  2. 标签 (Label):对节点进行分组分类(类似关系型数据库中"表"的概念,且一个节点可拥有多个标签,如 (:Person:Founder))。
  3. 关系 (Relationship):连接两个节点的有向边,具有明确的方向和类型(如 -[:FOUNDED]->、-[:DEPENDS_ON]->)。
  4. 属性 (Property):附加在节点或关系上的键值对(Key-Value),用于存储结构化数据(如节点属性 {name: "乔布斯", birth: 1955},关系属性 {since: 1976})。
graph LR
    A["(:Person {name: 'Steve Jobs'})"] -->|"[:FOUNDED {since: 1976}]"| B["(:Company {name: 'Apple'})"]
    B -->|"[:PRODUCED]"| C["(:Product {name: 'iPhone'})"]
Cypher 查询语言

Cypher 是 Neo4j 原生的声明式图查询语言,采用直观的 ASCII 艺术箭头语法 (节点)-[关系]->(节点) 来描述图模式,使查询逻辑贴近人类对关系的自然表达:

// 查询创立了 Apple 公司的所有人姓名
MATCH (p:Person)-[:FOUNDED]->(c:Company {name: 'Apple'})
RETURN p.name;

// 查找两度关系以内的所有上下游(多跳推理)
MATCH (c:Company {name: 'Apple'})-[*1..2]-(related)
RETURN related;

检索策略

检索方式 最优场景 弱项
向量检索 (Vector) 语义相似,同义词/改写 精确词元、多跳推理
BM25 精确词元、日期/代码 语义理解
图谱检索 (Graph) 多跳关系推理 模糊语义查询
RRF 融合 覆盖所有场景 依赖各路质量
                   ┌─────────────┐
                   │    Query    │
                   └──────┬──────┘
          ┌───────────────┼───────────────┐
          ▼               ▼               ▼
   向量检索(Vector)   BM25 检索      图谱检索(Graph)
   语义相似度          精确词元匹配    多跳关系遍历
          └───────────────┼───────────────┘
                          ▼
                   RRF 融合排序
                   score = Σ 1/(k + rank)
                          ▼
                   最终排序结果

RRF(Reciprocal Rank Fusion)

RRF 是一种无参数的排名融合算法,将多路检索器的排名列表合并为一份最终排序,只依赖排名、不依赖原始分数,因此无需对不同检索器的分数做归一化。

\[ \text{RRF}(d) = \sum_{r \in R} \frac{1}{k + \text{rank}_r(d)} \]
  • \(R\):所有检索器的结果列表集合
  • \(k\):平滑常数(默认 60),用于抑制头部排名过度主导,使排名靠后的文档也能贡献有效分数
  • \(\text{rank}_r(d)\):文档 \(d\) 在检索器 \(r\) 中的排名(从 1 开始)

核心优势: - 无需分数归一化——向量/BM25/Graph 三路分数尺度不同也能直接合并 - 只关心排名——对各检索器的打分分布无假设 - 多路投票效应——被多个检索器同时召回的文档会获得更高的综合分

MMR(Maximal Marginal Relevance)

MMR 在保证相关性的同时引入多样性约束,防止检索结果中出现大量语义重复的文档片段:

\[ \text{MMR}(d_i) = \lambda \cdot \text{Sim}(q, d_i) - (1-\lambda) \cdot \max_{d_j \in S} \text{Sim}(d_i, d_j) \]
  • \(\text{Sim}(q, d_i)\):文档 \(d_i\) 与查询 \(q\) 的相关性(如余弦相似度)
  • \(\max_{d_j \in S} \text{Sim}(d_i, d_j)\):文档 \(d_i\) 与已选集合 \(S\) 中最相似文档的相似度
  • \(\lambda\):权衡参数(0~1),\(\lambda\) 越大越偏向相关性,越小越偏向多样性

典型用途:当 top-K 检索结果存在大量近似重复片段时,使用 MMR 重排序可以显著提升上下文覆盖度,让 LLM 获得更全面的参考信息。

Cross-Encoder Rerank

Cross-Encoder 是一种精排模型,将 (query, document) 拼接为一个序列送入 Transformer,直接输出相关性得分。相比检索阶段使用的 Bi-Encoder(分别编码 query 和 document 再算相似度),Cross-Encoder 能捕捉更细粒度的交互语义,但计算成本更高。

对比 Bi-Encoder Cross-Encoder
输入方式 query 与 doc 分别编码 query + doc 拼接编码
速度 快(可预计算向量) 慢(每对都需推理)
精度 较高 更高(捕捉交互特征)
典型角色 粗排 / 召回 精排 / Rerank

工业实践:先用向量检索 + BM25 粗排召回 top-K 候选(如 50~100 篇),再用 Cross-Encoder 对候选集精排,取 top-N(如 5~10 篇)送入 LLM,在精度与延迟间取得平衡。

综合以上策略,工业级 RAG 系统的典型架构为:Vector + BM25 + Graph 三路并行召回 → RRF 融合 → MMR 去重 → Cross-Encoder 精排,逐层筛选出最终送入 LLM 的高质量上下文。

记忆

LLM 本身是无状态的——每次请求都是独立的。Agent 的"记忆"系统负责在多轮对话和跨会话之间持久化关键信息,让 Agent 具备上下文连贯性和个性化能力。

记忆类型

类型 机制 特点
短期记忆(滑动窗口) 按 Token 数或消息条数保留最近 N 条对话 实现简单,但窗口外的信息直接丢失
上下文压缩 对话达到阈值时,用 LLM 将历史摘要为精简版本 节省 Token,保留关键语义,但有信息损耗
长期记忆(向量库) 将重要信息向量化存储,按语义检索召回 跨会话持久化,支持大规模记忆

记忆检索与打分

当记忆条目积累到一定规模后,需要对召回的记忆进行综合打分排序,决定哪些记忆注入当前上下文:

因子 含义 计算方式
相关性 (Relevance) 与当前查询的语义相似度 向量检索 raw score
近期性 (Recency) 越久未访问得分越低 exp(-decay_per_hour × hours)
重要性 (Importance) 写入时标注的长期权重 0~1,无需再归一化

检索策略选型:

场景 推荐方案 原因
编程类系统 BM25 + 正则 精确匹配函数名、变量名等结构化信息,可覆盖 90%+ 场景
对话类系统 BM25 + ANN(向量检索) 需兼顾精确匹配与语义理解

BM25/关键词检索的优势在于精确性和高性能,但缺乏语义理解能力;向量检索擅长语义匹配但精确匹配差。两者互补使用效果最佳。

记忆生命周期管理

记忆不是只增不减的——需要冷热分离与分层压缩:高价值信息沉淀为长期记忆,低价值和过时信息逐步遗忘,避免噪音记忆污染召回质量。

当新记忆与已有记忆冲突时,需要选择合适的更新策略:

策略 做法 适用场景
Last-Write-Wins 同 key 直接用新值覆盖旧值 偏好、当前目标、当前阻塞点(默认首选)
版本化 + 失效标记 不物理删除;旧记录标记 status=stale / superseded_by=新id;检索只取 active 需要审计或回放"为什么改过"
Merge 合并 同主题互补、非互斥 → 合成一条 多条可并存的偏好/禁止项(如约束列表)
冲突升级 两边都像真又互斥 → 问用户或交由 Reflector 裁决 高风险事实(权限、账号、业务规则)
时间窗 / TTL 临时状态设过期,到期自动遗忘 短期事实(如"这周在赶 DDL"),避免抢占长期偏好的召回

Mem0

Mem0 是一个开源的 Agent 记忆管理框架,提供开箱即用的记忆提取、存储、检索和更新能力,支持自动从对话中识别并持久化关键信息。

核心流程:

用户对话 → LLM 提取记忆事实 → 去重/冲突检测 → 存储(向量库 + 图谱)→ 下次对话时语义检索召回

关键特性:

特性 说明
自动记忆提取 用 LLM 从对话中抽取关键事实(偏好、约束、背景),无需手动标注
双存储引擎 向量库(语义检索)+ 知识图谱(关系推理),互补召回
记忆去重与更新 新记忆写入时自动检测冲突,支持合并/覆盖/版本化
多层级记忆 支持 User / Agent / Session 三个粒度的记忆隔离
多模型支持 兼容 OpenAI、Anthropic、本地模型等

代码示例:

from mem0 import Memory

m = Memory()

# 添加对话,Mem0 自动提取并存储记忆
m.add("我喜欢用 Python,偏好 FastAPI 做后端", user_id="alice")
m.add("我的项目用的是 PostgreSQL 数据库", user_id="alice")

# 语义检索相关记忆
results = m.search("帮我选一个 ORM 框架", user_id="alice")
# → 召回: "喜欢 Python"、"使用 PostgreSQL"

# 查看用户所有记忆
m.get_all(user_id="alice")

# 记忆更新(自动检测冲突并覆盖)
m.add("我们已经从 PostgreSQL 迁移到 MySQL 了", user_id="alice")
# → 旧记忆 "PostgreSQL" 被更新为 "MySQL"

适用场景:需要快速为 Agent 集成记忆能力、且不想从零搭建记忆管线(提取→去重→存储→召回)的项目。

Agent 规划模式

规划模式决定了 Agent 如何把复杂目标拆解为具体行动。常见的主流模式如下:

ReAct (Reasoning + Acting) - 动态循环规划

  • 核心机制:Thought → Action → Observation 闭环循环。LLM 走一步看一步,根据上一步的执行结果(Observation)动态决定下一步是继续调用工具还是给出最终答复。
  • 适用场景:探索性、结果不确定、依赖外部反馈的任务(如查阅多层关联资料、排查报错日志)。
  • 工程痛点与解法:
  • 容易死循环或早退:仅靠 LLM 自身判断容易陷入重复调用或幻觉提前终止。
  • 工程实践:通常在外部宿主程序中增加 最大步数限制(Max Steps),或引入**状态机/校验器(Validator)**强制进行状态流转判断。

Plan-and-Execute - 显式拆解规划

  • 核心机制:两阶段分离。由 Planner 先完整拆解出子任务列表(Step 1...N),再交由 Executor 逐个执行,最后由 Summarizer 汇总。
  • 适用场景:步骤明确的长链路任务(如“编写某主题的行业调研报告并导出为 PDF”)。
  • 优缺点:
  • 优点:执行成本可控,全局结构清晰,便于展示步骤进度条。
  • 缺点:前期规划容易跟不上现实变化。若前置步骤失败,容易引起连锁雪崩(通常需配合 Plan-and-Solve / 动态重规划 Replanner)。

Reflection (Self-Refine) - 反馈式自我演进

  • 核心机制:Action → Evaluation → Reflection → Retry。Agent 产出初步结果后,由专门的 Evaluator/Critic 检查打分,若不合格则输出修改意见,LLM 据此反思并迭代。
  • 适用场景:有明确评价标准、对准确率要求高的任务(如代码生成、SQL 编写、长文本润色)。
  • 优缺点:大幅提升单次输出质量,但会带来多倍的延迟(Latency)与 Token 成本消耗。

Tree of Thoughts (ToT) - 搜索式树状规划

  • 核心机制:将思考过程建模为树结构,每一步生成多个潜在候选思路(分支),借助 BFS(广度优先)/ DFS(深度优先)或评分机制评估各分支价值,并支持回溯(Backtracking)。
  • 适用场景:需要全局试错与多步博弈的复杂决策(如 24点游戏、数独、策略制定、算法设计)。
  • 优缺点:推理能力上限最高,但调用次数指数级膨胀,通常限于离线高价值场景。

模式对比与选型指南

模式 思考时机 适应环境变化能力 Token/延迟成本 适用典型场景
ReAct 边走边想 ⭐⭐⭐⭐⭐(强,随时调整) 中等 动态排错、多跳信息检索
Plan-and-Execute 想好再走 ⭐⭐(偏弱,静态为主) 低 结构化流程、标准多步骤任务
Reflection 做完复盘 ⭐⭐⭐(中等) 较高 代码/文案生成质量调优
Tree of Thoughts 穷举推演 ⭐⭐⭐⭐(支持回溯) 极高(成倍翻番) 复杂逻辑推理、算法解题

Multi Agent

3种模式

请求
│
▼
[Retriever] ──▶ [Reranker] ──▶ [Generator] ──▶ [Verifier] ──▶ 响应
                ┌─── Retriever ──┐
                │                │
用户 ──▶ Orchestrator ─── Reranker ───▶ 合成回复
                │                │
                └─── Generator ──┘
        写入              读取
Agent A ──────▶ Blackboard ◀────── Agent C
Agent B ──────▶     │     ◀────── Agent D
                    │
            变更通知(事件)

3 种模式的对比:

维度 Pipeline Hub-and-Spoke Blackboard
复杂度 低 中 高
调试难度 易 中 难
并行能力 低 高 高
适合任务 线性 多角色协作 迭代协商
典型实现 Redis Queue FastAPI + gRPC DB + Pub-Sub

通信机制

机制 代表技术 延迟 耦合度 适用场景
Sync RPC HTTP / gRPC 低 高 实时决策、简单编排
Async Queue Redis / Kafka / SQS 中 低 耗时操作、高并发
Pub-Sub SNS / Kafka Topic 中 很低 广播事件、多订阅方
Shared Storage S3 + DB + 信号 高 很低 大文件、artifacts 共享

优雅降级

场景:Reranker 服务不可用时,系统不应整体崩溃,而应降级继续提供服务。

正常路径:  retrieve → rerank → generate  ✅
降级路径1: retrieve → (skip rerank) → generate  ⚠️ 质量略降
降级路径2: (retrieve timeout) → return cached snippets  ⚠️ 更大降级
兜底路径:  return static fallback message  🆘

三条铁律

  1. 每条消息带 request_id,处理前先做幂等检查
  2. 每个 Agent 暴露 latency + status,不监控等于盲飞
  3. 提前设计失败路径,不要等故障发生后再想降级逻辑

常用框架

Microsoft Agent Framework/AutoGen 与 CrewAI

LangGraph

LangGraph 是 LangChain 团队推出的底层 Agent 编排框架,把 Agent 的执行过程建模为一张有状态的图。与 LangChain 早期的 Chain(线性 DAG)不同,LangGraph 的核心卖点是支持循环——这正是 ReAct 这类「思考 → 调工具 → 观察 → 再思考」模式所需要的。

核心概念

概念 含义 代码实现
State 在节点间共享、流转的数据状态,是图的「内存」 TypedDict / Pydantic BaseModel,字段可用 Annotated[..., reducer] 指定合并方式
Node 执行一步具体工作(调模型、调工具、业务逻辑) 普通函数 (state) -> dict,返回的是状态的增量更新而非完整状态
Edge 决定下一步执行哪个节点 add_edge(固定边)、add_conditional_edges(条件边)、START / END 虚拟节点
Reducer 多个节点写同一字段时如何合并 默认覆盖;operator.add 追加;add_messages 按消息 ID 追加/更新
Graph 由节点和边组成的有向图(允许有环) StateGraph(State) → .compile() 得到可执行的 CompiledGraph
Checkpointer 每步执行后保存状态快照,是记忆、中断、恢复的基础 InMemorySaver、SqliteSaver、PostgresSaver,按 thread_id 隔离会话

最小示例:

from typing import Annotated, TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.checkpoint.memory import InMemorySaver

class State(TypedDict):
    messages: Annotated[list, add_messages]  # 追加而非覆盖

def chatbot(state: State):
    return {"messages": [llm.invoke(state["messages"])]}  # 只返回增量

builder = StateGraph(State)
builder.add_node("chatbot", chatbot)
builder.add_edge(START, "chatbot")
builder.add_edge("chatbot", END)

graph = builder.compile(checkpointer=InMemorySaver())
graph.invoke({"messages": [("user", "hi")]}, {"configurable": {"thread_id": "1"}})

控制流

方式 作用 典型场景
固定边 add_edge(a, b) a 执行完必然走 b 线性流水线
条件边 add_conditional_edges(a, router) 根据 router(state) 的返回值选择下一个节点 判断是否需要调工具、意图路由
循环 条件边指回之前的节点 ReAct:agent → tools → agent,直到不再调工具才走 END
并行(扇出/扇入) 一个节点连多条边,下游节点在同一步并发执行,结果经 reducer 合并 多路检索、多角度分析
Send(Map-Reduce) 在运行时动态决定分发几个并行任务,每个任务携带独立输入 对 N 篇文档各生成摘要后汇总
Command 节点内同时完成「更新状态 + 跳转」,无需预先声明条件边 Multi-Agent 之间的 handoff
子图(Subgraph) 把一张编译好的图当作另一张图的节点 模块化复用、Multi Agent 分层

ReAct 循环的典型写法:

from langgraph.prebuilt import ToolNode, tools_condition

builder.add_node("agent", call_model)
builder.add_node("tools", ToolNode(tools))
builder.add_edge(START, "agent")
builder.add_conditional_edges("agent", tools_condition)  # 有 tool_calls → "tools",否则 → END
builder.add_edge("tools", "agent")                       # 形成循环

防止死循环:调用时传 {"recursion_limit": 25},超过步数会抛出 GraphRecursionError。

中断

中断是 LangGraph 实现 Human in the Loop 的机制:图执行到某处暂停,把状态持久化到 Checkpointer,等待人工输入后再从断点继续。必须配置 Checkpointer 和 thread_id,否则无法恢复。

两种方式:

方式 写法 特点
动态中断(推荐) 节点内调用 interrupt(payload) 可以按条件中断,并把上下文信息抛给前端
静态断点 compile(interrupt_before=["tools"]) / interrupt_after 在指定节点前/后固定暂停,多用于调试
from langgraph.types import interrupt, Command

def human_review(state: State):
    decision = interrupt({"question": "是否执行该操作?", "tool_call": state["tool_call"]})
    if decision == "approve":
        return Command(goto="execute")
    return Command(goto=END)

config = {"configurable": {"thread_id": "order-42"}}
graph.invoke(inputs, config)                 # 执行到 interrupt 处暂停,返回 __interrupt__ 信息
graph.invoke(Command(resume="approve"), config)  # 带着人工决定恢复执行

常见 HITL 模式:

  • 审批:高风险工具调用(转账、删库、发邮件)前要求人工确认
  • 编辑状态:人工修改模型生成的草稿/参数后再继续
  • 补充信息:Agent 缺少关键参数时向用户追问

注意事项:

  • 恢复时节点会从头重新执行(而非从 interrupt() 那一行继续),所以 interrupt() 之前的代码要保证幂等,副作用操作放到中断之后
  • 同一节点内有多个 interrupt() 时按调用顺序匹配 resume 值,不要把它放在顺序不固定的逻辑里
  • 借助 Checkpointer 还能做时间旅行:get_state_history() 查看历史快照,从任意 checkpoint 分叉重跑

编排与持久化

Agent 任务是分钟级甚至小时级的,而非毫秒级的普通 RPC 调用,进程重启、模型超时、工具报错都可能发生在任务执行到一半时。因此长链路 Agent 需要一层持久化编排(如 Temporal),提供状态持久化、失败重试、任务队列与定时器等能力,让任务可以从中断处恢复而不是从头重跑。

LangGraph 解决的是单次运行内的流程编排,Temporal 解决的是跨进程、跨重启的任务可靠性,两者互补。

MCP

MCP(Model Context Protocol)是 Anthropic 提出的开放协议,用于标准化 LLM 应用与外部工具、数据源之间的连接方式,可以理解为 AI 应用的 "USB-C 接口"。

解决的问题:没有统一协议时,M 个 AI 应用对接 N 个工具需要 M×N 份适配代码;有了 MCP,工具只需实现一次 MCP Server,就能被所有支持 MCP 的应用复用,复杂度降为 M+N。

Tool Call 是模型层面"如何调用工具"的能力,MCP 是工程层面"工具如何被发现和接入"的协议,MCP 底层仍然依赖模型的 Tool Call 能力

架构

┌──────────────── Host(Claude Desktop / IDE / Agent)────────────────┐
│   MCP Client ①          MCP Client ②          MCP Client ③          │
└───────┬──────────────────────┬─────────────────────┬────────────────┘
        │ 1:1                  │ 1:1                 │ 1:1
   MCP Server             MCP Server            MCP Server
   (GitHub)               (数据库)               (文件系统)
  • Host:用户直接使用的 AI 应用,管理多个 Client
  • Client:Host 内部与某个 Server 保持 1:1 连接的组件
  • Server:对外暴露能力的轻量服务,封装具体的工具或数据源

通信基于 JSON-RPC 2.0,传输方式有两种:

传输方式 场景
stdio Server 作为本地子进程运行,适合访问本地文件、命令行工具
Streamable HTTP Server 远程部署,支持多客户端,远程场景需做鉴权(OAuth)

核心能力

能力 提供方 控制方 说明
Tools Server 模型决定调用 可执行的操作,如查询数据库、创建 Issue
Resources Server 应用决定加载 只读的上下文数据,如文件内容、数据库 Schema
Prompts Server 用户主动选择 预定义的提示词模板
Sampling Client Server 发起 Server 反过来请求 Host 的模型生成内容
Elicitation Client Server 发起 Server 在执行中向用户追问信息

注意事项

  • 上下文膨胀:每个 Tool 的定义都会占用上下文,接入过多 Server 会挤占 Token 并降低工具选择的准确率,应按需加载
  • 安全风险:第三方 Server 可能在工具描述或返回结果中植入恶意指令(工具投毒 / 间接 Prompt 注入),接入前需审查来源并控制权限(参见护栏)

Harness

Agent = Model + Harness。Harness 指模型之外的整套运行时"脚手架",负责把一个只会生成文本的 LLM 变成能持续完成任务的 Agent。同一个模型放在不同的 Harness 里,实际效果可能差距很大。

Harness 通常包含:

组件 职责
Agent Loop 驱动 "思考 → 调用工具 → 观察结果" 的循环,决定何时结束
工具系统 内置工具(读写文件、执行命令、搜索)+ MCP 扩展
上下文管理 组织 System Prompt、压缩历史、控制 Token 预算(参见成本优化)
记忆 跨会话持久化用户偏好与项目知识(参见记忆)
权限与沙箱 限制可执行的操作,高风险操作需要确认(参见护栏)
扩展机制 Skills、Hooks、Sub-Agent 等

与 LangGraph 这类框架的区别:框架提供搭建 Agent 的积木,需要自己组装流程;Harness 是开箱即用的完整运行时,典型代表有 Claude Code、Codex CLI、Hermes Agent

Hermes Agent

Nous Research 于 2026 年 2 月开源的 Agent Harness,与该团队的 Hermes 系列模型同名但不是一回事。它与模型无关,可接入各类闭源和开源模型,定位是长期运行的个人助手。

主要特点:

  • 自我进化的 Skills:从成功完成的任务轨迹中自动沉淀 Skill,并在后续使用中持续改进
  • 持久记忆:跨会话记住用户相关的事实,并可检索自己过去的对话
  • 多平台接入:通过消息网关连接 Telegram、Discord、Slack 等
  • 对开源模型友好:官方主打的卖点之一是更适合搭配开源模型使用

护栏

护栏(Guardrails)是在 Agent 执行链路上设置的检查点,用于拦截不安全的输入、输出和操作。按所处位置可分为三层:

输入护栏(Before Agent)

  • Prompt 注入检测:识别"忽略之前的指令"等越狱话术。除了用户直接输入,更要警惕间接注入——RAG 检索到的文档、网页、工具返回结果中夹带的恶意指令
  • 有害内容过滤:暴力、恐怖、违法等内容
  • PII 检测:避免敏感信息进入模型或被写入日志、记忆

输出护栏(After Agent)

  • 有害内容 / PII 过滤:防止模型输出违规内容或泄露敏感信息
  • 格式与事实校验:结构化输出校验、幻觉检测(参见评估中的 Faithfulness)

工具调用护栏

  • 最小权限:只暴露完成任务所需的工具,只读/写权限分开
  • 参数校验:校验调用参数是否在白名单或合法范围内
  • 人工审批:转账、删除、发邮件等高风险操作前走 Human in the Loop(参见中断)

PII 处理策略

检测身份证号、手机号、邮箱、信用卡号等敏感信息后,常见处理方式(以 LangChain PIIMiddleware 为例):

策略 行为 是否保留可辨识性 典型场景
redact 整段替换为 [REDACTED_类型] 否 合规、日志脱敏
mask 部分遮盖,保留少量尾部可读信息 部分 客服界面、人工核对
hash 替换为确定性哈希 <类型_hash:摘要> 是(假名化,可关联同一值) 分析、排错
block 检测到即抛出异常(PIIDetectionError) N/A 严禁出现该类信息

手机号、身份证号取值空间小,普通哈希可被穷举还原,hash 策略应使用带密钥的 HMAC

实现方式

方式 优点 缺点
基于规则(正则、关键词、黑白名单) 快、便宜、结果确定 容易被改写、编码绕过
基于模型(LLM 语义判断、Llama Guard 等安全分类模型) 能理解语义,覆盖面更广 慢、贵、存在误判

实践中通常分层组合:规则先行拦截明显违规且成本低,模型兜底处理语义层面的风险

评估

RAG 系统的评估需要同时衡量检索质量和生成质量两个维度。当前主流方案采用 LLM-as-Judge——用一个 LLM 对另一个 LLM 的输出进行自动化评分,替代人工标注。

核心指标

检索质量(评估检索器是否找到了正确且精准的上下文):

指标 含义 参考阈值 低分原因 优化方向
Context Recall 检索结果是否覆盖了回答所需的全部信息 0.8–0.9 top_k 太小;chunk 太大;Embedding 召回差 增大 topk;缩小 chunksize;更换 Embedding 模型
Context Precision 检索结果中有多少是真正相关的(信噪比) 0.7–0.85 召回了大量无关片段 增加 Rerank;提高相似度阈值;改善文档质量

Precision 与 Recall 是此消彼长的关系

生成质量(评估 LLM 是否基于上下文给出了准确且切题的回答):

指标 含义 参考阈值 低分原因 优化方向
Faithfulness 答案是否忠实于检索到的上下文(无幻觉) 0.85–0.95 System Prompt 约束弱;检索内容不足 强化 System Prompt 约束;优先提升 Recall
Answer Relevancy 答案是否切题回答了用户问题 0.8–0.9 Prompt 未引导直接回答;答案冗长绕弯 Query 重写;优化 Response Prompt

调优优先级:Recall → Faithfulness → Precision → Relevancy 检索召回是一切的基础——如果相关文档根本没被检索到,后续的精排和生成都无法挽救。

MRR(Mean Reciprocal Rank)

MRR 衡量的是第一个正确结果出现的排名位置,是检索系统常用的评估指标:

\[\text{MRR} = \frac{1}{|Q|}\sum_{i=1}^{|Q|}\frac{1}{\text{rank}_i}\]

其中 \(\text{rank}_i\) 是第 \(i\) 个查询中首个正确结果的排名。例如三次查询的首个正确结果分别排在第 1、3、2 位,则 \(\text{MRR} = \frac{1}{3}(\frac{1}{1} + \frac{1}{3} + \frac{1}{2}) \approx 0.611\)。

MRR 只关心第一个命中的位置,适用于"用户只看第一条结果"的场景(如问答、实体查找)。若需评估整体排序质量,应结合 Precision/Recall 使用。

评估框架:Ragas & DeepEval

对比 Ragas DeepEval
定位 专注 RAG 评估的轻量框架 通用 LLM 评估平台(覆盖 RAG + Agent + 对话)
指标 Faithfulness、Answer Relevancy、Context Precision/Recall 同名指标 + Hallucination、Toxicity、Bias 等
LLM-as-Judge 默认 OpenAI,可切换任意 LLM 同上,支持自定义评估模型
集成 LangChain、LlamaIndex LangChain、LlamaIndex、Pytest(deepeval test run)
可视化 需搭配外部工具 内置 Confident AI 云端仪表盘
适用场景 快速验证 RAG Pipeline CI/CD 集成、回归测试、多维度综合评估

DeepEval 额外支持 HallucinationMetric 幻觉检测

生产可观测性:Langfuse

Langfuse 是开源的 LLM 可观测性平台,专注于生产环境的追踪与监控,与 Ragas/DeepEval 的离线评估形成互补:

能力 说明
Tracing 端到端追踪每次 LLM 调用链路(检索 → 增强 → 生成),记录输入/输出、耗时、Token 消耗
成本监控 按模型、用户、会话维度统计 Token 用量与费用
在线评估 支持接入 LLM-as-Judge 对生产流量实时打分(Faithfulness、Relevancy 等)
Prompt 管理 版本化管理 Prompt 模板,支持 A/B 测试与回滚
数据集管理 从生产 Trace 中提取 case 构建评测数据集,反哺离线评估

与 Ragas/DeepEval 的协作模式:

开发阶段                          生产阶段
┌──────────────────┐            ┌──────────────────┐
│  Ragas/DeepEval  │            │     Langfuse     │
│  离线跑评测集      │            │  追踪生产流量      │
│  验证指标达标      │───上线──→   │  在线评估打分      │
│                  │            │  发现 bad case    │
└──────────────────┘            └────────┬─────────┘
        ▲                                │
        └────── 提取 case 反哺评测集 ──────┘

一句话总结:Ragas/DeepEval 管"上线前够不够好",Langfuse 管"上线后跑得怎么样",两者结合形成评估闭环。

成本优化

Agent 的 Token 消耗随调用轮数和上下文长度快速放大,常见的降本手段:

  • 模型路由:简单任务交给便宜的小模型,只有复杂任务才用大模型
  • Prompt Cache:复用重复的前缀,避免每轮都按原价重新计算
  • 上下文压缩:对历史对话做摘要、裁剪无关的工具返回结果(参见记忆)
  • 限制输出长度:设置 max_tokens,要求结构化的简洁输出
  • Batch API:离线、非实时任务走批处理接口,价格通常有较大折扣

模型路由

方式 做法 特点
规则路由 按任务类型、输入长度、用户等级等规则分配模型 简单可控,但规则难以覆盖所有情况
分类器路由 用小模型或专门训练的 Router 先判断难度,再选择模型 更智能,但路由本身也有成本和误判
级联(Cascade) 先用小模型回答,校验不通过或置信度低时再升级到大模型 大部分请求由小模型完成,但失败的请求延迟更高

切换模型会导致 Prompt Cache 失效,同一会话内应尽量固定模型

Prompt Cache

原理是前缀匹配:只有从头开始完全一致的部分才能命中缓存,中间任何一个字符不同,其后的内容全部失效。这一点类似 MySQL 联合索引的最左前缀原则。

提高命中率的做法:

  • 静态内容在前,动态内容在后:按 工具定义 → System Prompt → 固定示例 → 历史对话 → 本轮输入 的顺序组织
  • 不要在前缀中放入易变内容:比如 System Prompt 里的当前时间、请求 ID、随机排序的工具列表、键顺序不固定的 JSON
  • 对话历史只追加不修改:中途改写或删除早期消息会让后续缓存全部失效
  • 注意 TTL:缓存有过期时间(如 Anthropic 默认 5 分钟,每次命中会刷新)。间隔较长的场景可以定时发送轻量请求保活,或者选用更长的 TTL,前提是保活成本低于缓存重建成本

各厂商实现不同:OpenAI 自动缓存,Anthropic 需要通过 cache_control 显式标记缓存断点,且都有最小缓存长度限制。命中情况可通过响应中的 usage 字段(如 cached_tokens / cache_read_input_tokens)观察

Gateway

LLM Gateway 位于应用和模型供应商之间,用统一接口屏蔽不同厂商 API 的差异,并集中处理横切关注点:

  • 统一接口:以 OpenAI 兼容格式调用各家模型,切换供应商无需改业务代码
  • 路由与容灾:负载均衡、失败重试、跨模型/跨供应商 fallback
  • 成本管控:虚拟 Key、按团队/项目设置预算与限流、跨供应商成本统计
  • 可观测性:统一记录请求日志、延迟、Token 用量
  • 附加能力:响应缓存、护栏(参见护栏)

常用方案:

方案 特点
LiteLLM 开源,Python SDK + Proxy Server,可自部署,支持的模型供应商很多
Portkey 提供开源 Gateway 和托管平台,内置虚拟 Key、预算、fallback、护栏等企业级功能

评论