Jean's Blog

一个专注软件测试开发技术的个人博客

0%

LangChain中的上下文工程

上下文工程的说明

上下文工程是AI工程师最重要的技能 — 它是连接理论与实践,将AI从“演示天才”转变为“实战高手”的关键桥梁。拆解了将 AI 从理论构想落地为实际可用成果的关键技能体系,分为三大核心能力模块,每个模块都有明确的能力定义、执行要求和价值目标,具体解读如下:

一、清晰的信息指令

这是AI 理解任务的基础,核心目标是消除歧义、让 AI 精准捕捉需求。

  • 核心要求:指令必须精准、简洁、无歧义,清晰描述任务目标、对应方法、相关背景、约束条件。
  • 关键动作
    1. 明确告诉 AI “要做什么”(任务);
    2. 补充 “怎么做”(方法 / 逻辑);
    3. 限定 “在什么范围 / 条件下做”(背景、限制)。
  • 价值:避免 AI 误解意图、偏离方向,减少后续修正成本,让 AI 输出贴合真实需求。

二、合格的工具技能

这是AI 执行任务的支撑,核心目标是具备完成任务的完整能力储备。

  • 核心要求:掌握 AI 完成任务所需的全维度工具,覆盖数据、接口、应用、文档、代码等。
  • 包含范畴
    1. 数据:可用的素材、样本、参考资料;
    2. API / 应用:可调用的工具、平台、功能模块;
    3. 文档 / 代码:可参考的规范、脚本、执行程序。
  • 价值:让 AI 拥有 “落地执行的资本”,具备完成复杂任务、解决实际问题的能力,而非仅停留在理论层面。

三、规范的指令格式

这是AI 高效输出的保障,核心目标是标准化输出、提升处理效率与结果质量。

  • 核心要求:采用标准化、结构化、条理化的格式呈现指令与工具。
  • 关键动作
    1. 规范排版、分类呈现指令和工具;
    2. 清晰标注重点、逻辑分层;
    3. 统一格式、统一用语。
  • 价值:让 AI 快速识别结构、抓取重点,高效处理需求,最终输出精准、规范、可控、可复用的结果,避免混乱、遗漏、错误。

整体核心逻辑总结

三大能力层层递进:

清晰指令(让 AI 懂) → 合格工具(让 AI 会) → 规范格式(让 AI 快且准)

最终目的:把 AI 从 “理论上的天马行空”,转化为可落地、可复用、可落地应用的实战成果,完成从理论认知到工程实践的关键转化。

为什么智能体会失败?

原因主要有两个:

  1. AI 模型本身能力不足

    就像工人本身技术不行,记不住太多东西,自然无法处理长对话、长文本。

  2. 没有给对 “上下文”

    就像工人很能干,但你没给他项目资料、背景、清晰指令,他就只能按有限信息去做,导致 “失忆”。

绝大多数 “失忆” 问题,都是因为第二个原因:没有给对、给全上下文。不是模型笨,而是你没把必要的背景、资料、历史对话喂给它

LangChain 的设计目的,就是帮你轻松管理和传递上下文,让智能体不会丢内容、不会忘事,能持续理解完整信息。

智能体(Agent)的工作原理

智能体(Agent)的工作原理,核心是一个循环闭环流程:智能体在 “思考 — 行动” 之间不断循环,自主完成任务。

核心流程:

  1. 思考与规划:智能体先分析任务、制定行动思路与计划。
  2. 判断是否使用工具:根据需求判断是否需要调用工具。
    • 不需要:直接生成最终答案。
    • 需要:执行 AI 工具行动。
  3. AI 工具执行行动:调用工具完成具体操作。
  4. 获取结果:拿到工具执行后的结果。
  5. 循环判断:回到 “是否需要工具” 继续判断,直到任务完成。
  6. 任务完成:最终达成目标,结束流程。

关键:你的角色是把控这个循环里的每一个环节。

flowchart TD
    A[开始任务] --> B[思考/规划]
    B --> C{是否需要使用工具?}

    %% 不需要工具分支
    C -->|否| D[生成答案]
    D --> E[任务结束]

    %% 需要工具分支(循环)
    C -->|是| F[AI工具行动]
    F --> G[获取结果]
    G --> C

智能体(Agent)的三大控制维度

核心是通过精细化管理上下文,让 AI 更精准、可控地完成任务,分为控制维度、内容、特点、作用四部分,同时补充了数据三大来源

三大控制维度(核心)

  1. 控制维度:上下文上

    • 内容:AI 单次能看到的东西(参考范围)
    • 特点:有上限、有范围
    • 作用:让 AI 只看指定内容,不看无关内容
  2. 控制维度:上下文下

    • 内容:指令、规则、格式、要求、例子
    • 特点:指令越细、越具体,产出越精准
    • 作用:控制 AI 的输出风格、格式、内容边界
  3. 控制维度:上下文前后

    • 内容:在 “思考” 和 “行动” 之间发生了什么(如当天记录、安全记录)
    • 特点:会改变整个执行流程
    • 作用:记录过程、复盘、保证安全

数据的三个来源

智能体执行任务时,会从三类信息中读取内容:

  1. 运行时上下文:正在执行的任务、当前指令、本次对话内容
  2. 状态上的记忆:历史记录、之前的对话、过往的临时信息
  3. 公司中的知识:公司内部文档、数据、所有可调用的信息(可用 API、工具读取)

总结

  • 三大上下文控制 = 范围限制 + 指令控制 + 过程记录
  • 三大数据来源 = 实时任务 + 历史记忆 + 企业知识
  • 最终目标:精细化管理 AI 行为,让输出更精准、可控、安全。

实现机制:中间件(Middleware)

中间件允许开发者在智能体工作循环(Loop)的任何环节“插入”自定义代码。这就像是在一条自动化流水线上加装了自定义的检测仪或机械臂。

它主要用于实现以下两个功能:

  • 更新上下文: 例如在对话进行时,自动整理、压缩或提取聊天记录,确保模型始终能获取最相关的信息。
  • 控制流程: 根据特定逻辑拦截或修改指令,比如在某些条件下直接“跳过某个工具的调用”,从而优化执行路径。

控制AI的思考

控制每次给AI“投喂”什么信息。

系统提示 —— 动态工作指令

通俗解读:就像在会议中,老板根据会议进度,动态调整对秘书的要求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from langchain.agents.middleware import dynamic_prompt, model_request
from typing import Dict, Any

@dynamic_prompt
def custom_prompt(request: model_request) -> str:
"""根据对话长度调整模型请求"""
base = "you are a helpful assistant."
# 对话超过10轮,要求更简洁
if len(request.message_history) > 10:
base += "\nThis is a long conversation, be extra concise."
return base

# 应用创建
agent = create_agent(
tools=[],
llm=llm,
prompt=custom_prompt,
middleware=[state_aware_prompt]
)

代码解读

  1. 导入模块:从 LangChain 导入动态提示、模型请求相关工具与类型注解。
  2. 装饰器 @dynamic_prompt:标记函数为动态提示生成器,可根据上下文动态调整提示词。
  3. 自定义提示函数 custom_prompt
    • 基础指令:you are a helpful assistant.(你是一个有用的助手)。
    • 逻辑:若对话历史超过 10 轮,追加精简指令,让回复更简洁。
  4. 智能体创建 create_agent:配置空工具列表、大模型、自定义提示、中间件,完成智能体初始化。

消息管理 —— 智能背景信息注入

通俗解读:就像在秘书回答前,助理悄悄塞给他一张关于当前项目背景的小纸条。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@wrap_model_call
def inject_file_context(request: model_request, handler):
"""自动注入用户上传文件的上下文状态"""
# 提取上传文件信息
uploaded_files = request.state.get("uploaded_files", [])
if uploaded_files:
file_descriptions = []
for file in uploaded_files:
file_descriptions.append(f"- {file['name']}: {file['summary']}")
# 构建可用文件上下文
file_context = "\n".join(file_descriptions)
# 追加到用户消息中,不影响历史对话
messages = request.messages
messages.append({"role": "user", "content": file_context})
request.override_messages(messages)
return handler(request)

代码解读

  1. 装饰器 @wrap_model_call:用于包装模型调用,在模型回复前执行自定义逻辑。
  2. 上下文处理函数 context:功能:自动从上传文件中提取信息并注入到对话上下文。
  3. 提取上传文件:从 request.state 获取已上传文件列表 uploaded_files
  4. 生成文件描述:遍历文件,拼接文件名与摘要,形成 file_descriptions
  5. 构建文件上下文:用换行符连接所有文件描述,得到 file_context
  6. 追加用户消息:将文件上下文以用户角色追加到消息列表,不修改历史对话。
  7. 覆盖消息并执行:用新消息列表覆盖原消息,继续执行后续处理。

工具选择 —— 动态权限管理

通俗解读:就像给秘书分配权限。新访客只能用公共电脑,认证用户才能用内部系统。

1
2
3
4
5
6
7
8
9
10
11
12
13
@wrap_model_call
def state_based_tools(request: model_request, handler):
"""基于用户状态动态选择可用工具"""
is_authenticated = request.state.get("messages_authenticated", False)
if not is_authenticated:
# 未认证用户仅保留公开工具
tools = [t for t in request.tools if t.name.startswith("public_")]
request = request.override(tools=tools)
if message_count > 5:
# 对话超过5轮,添加高级搜索工具
tools = [t for t in request.tools if t.name == "advanced_search"]
request = request.override(tools=tools)
return handler(request)

代码解读

  1. 装饰器@wrap_model_call 包装模型调用,在生成回答前动态调整工具权限。
  2. 权限判断:根据用户认证状态,只保留公开工具
  3. 对话轮次控制:对话超过 5 轮,自动追加高级搜索工具
  4. 动态生效:实时覆盖工具列表,实现权限与能力的动态调整。

模型选择 —— 智能资源分配

通俗解读:就像派活。简单任务派给实习生,复杂项目派给资深专家。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 选择不同级别的AI模型
large_model = init_chat_model("claude-3-sonnet") # 豪华版
standard_model = init_chat_model("gpt-4o-mini") # 标准版
efficient_model = init_chat_model("qwen-plus") # 精简版

@wrap_model_call
def state_based_model(request: model_request, handler):
"""根据对话长度动态选择AI模型"""
message_count = len(request.messages)
# 对话长,使用豪华版
if message_count > 20:
model = large_model
# 对话中等,使用标准版
elif message_count > 10:
model = standard_model
# 对话短,使用精简版
else:
model = efficient_model
return handler(request.override(model=model))

代码解读

  1. 模型初始化:定义大、中、小三种不同能力的 AI 模型。
  2. 装饰器@wrap_model_call 拦截模型调用,动态切换模型。
  3. 对话长度判断:根据消息数量自动选择模型。
  4. 动态调度:对话越长,使用能力越强的模型;对话短则用轻量模型,节省成本并提升效率。

控制AI的行动能力

工具很特殊,它既能“读”取环境信息,也能“写”回结果。

工具定义 —— 清晰的使用说明书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from langchain.tools import tool
from tool.parse_docstring import true

@tool(parse_docstring=True)
def search_orders(user_id: str, status: str, limit: int=10) -> str:
"""
订单搜索
当用户询问订单历史或者订单状态时使用该工具
链接支持的查询状态:'pending', 'shipped', 'delivered'

Args:
user_id: 用户唯一标识
status: 订单状态,可选:'pending', 'shipped', 'delivered'
limit: 限制返回结果数量,默认10

Returns:
str: 找到的limit个orders for user_id
"""
return f"found {limit} orders for {user_id}"

代码解读

1. @tool(parse_docstring=True) 的魔力

这是这段代码的灵魂。在 LangChain 中,parse_docstring=True 告诉系统:请解析下面这段三引号里的文档字符串(Docstring)

  • 系统会自动将 Args 部分的内容转换为 JSON Schema。
  • AI 模型(如 GPT-4)在思考时,会看到这些描述,从而知道每个参数代表什么意思、该传什么格式。

2. 文档字符串(Docstring)的作用

在 Agent 开发中,文档字符串不是写给程序员看的注释,而是写给 AI 看的指令

  • 工具用途描述:告诉 AI 什么时候该用这个工具(例如:“当用户查询订单历史时…”)。
  • 参数枚举限制:明确告知 AI status 只能在 pending, shipped, delivered 这三个词里选,防止 AI 瞎编一个状态。

3. 强类型参数定义

代码中使用了 Python 的类型注解(Type Hints),如 user_id: str, limit: int

  • 这不仅方便代码补全,更重要的是 AI 会根据这些类型来提取参数。如果用户说“查 5 个订单”,AI 会自动将“5”识别为整数 5 传给 limit

工具读取 —— 获取环境信息

通俗解读:秘书去报销,不仅需要发票(AI提供的参数),还需要你的工号(从状态中读取)。

1
2
3
4
5
6
@tool
def check_authentication(runtime: ToolRuntime) -> str:
"""检查用户认证状态"""
# 从运行时环境读取认证状态
is_authenticated = runtime.state.get("authenticated", False)
return "User is authenticated" if is_authenticated else "User is not authenticated"

代码解读

这段代码展示了 AI 工具调用的一个进阶用法:状态感知(State Awareness)

  1. @tool 装饰器: 这标志着该函数是一个可以被 AI 模型调用的“工具”。AI 会根据函数名和文档字符串(docstring)来决定何时触发它。
  2. runtime: ToolRuntime 参数: 这是关键点。通常的工具只接收 AI 提取的参数(如“发票金额”),但这里引入了 runtime 对象。它代表了程序运行时的上下文环境,允许工具获取 AI 提示词之外的信息。
  3. 从状态(State)中读取runtime.state.get("authenticated", False) 并不是让 AI 告诉工具用户是否登录,而是直接从系统内存或数据库中提取当前的登录状态。

工具写入 —— 改变工作环境

通俗解读:秘书帮你办理入门手续后,不仅告诉你办好了,还给你发访客胸牌。之后所有门禁(其他工具)看到胸牌都会放行。

1
2
3
4
5
6
7
8
9
10
from langgraph.types import Command

@tool
def authenticate_user(password: str, runtime: ToolRuntime) -> Command:
"""用户认证工具"""
if password == "correct_password":
# 认证成功,永久更新会话状态
return Command(update={"authenticated": True})
else:
return Command(update={"authenticated": False})

代码解读

这段代码的核心在于:工具不再仅仅返回“话语”(字符串),而是返回“指令”(Command)。

  1. 引入 Command 对象:在普通的 AI 开发中,工具通常返回类似 "认证成功" 的文字,AI 只能靠“记忆”来记住这件事。而 langgraph.types.Command 允许工具直接干预系统的状态机

  2. 状态更新机制 (update)

  • 代码行为:当 password 正确时,工具返回 Command(update={"authenticated": True})
  • 底层影响:这会直接修改 LangGraph 维护的全局 State 字典。这意味着,“用户已认证”这个事实被刻在了系统的“账本”上,而不是仅仅存在于 AI 的聊天上下文里。
  1. 运行流程拆解

  2. 触发:用户输入密码,AI 识别并调用 authenticate_user 工具。

  3. 验证:代码在后台执行硬核逻辑判断(password == "correct_password")。
  4. 写回
    • 如果正确,全局变量 authenticated 变为 True
    • 如果错误,变为 False

生命周期上下文:自动化流程管理

控制“思考”和“行动”之间发生的所有事。

自动总结 — 解决AI“记忆有限”问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
from langchain.agents.middleware import SummarizationMiddleware

agent = create_agent(
"gpt-4o",
tools=[...],
middleware=[
SummarizationMiddleware(
model="gpt-4o-mini", # 使用便宜模型进行总结
trigger={"tokens": 4000}, # 达到4000token时触发
keep={"messages": 20}, # 保留最近20条原始消息
),
],
)

“会议记录本”的比喻非常传神:当本子写满时,助理把前半部分精炼成摘要抄在下一页开头,然后把旧的那几页撕掉。

关键参数解析:

  • SummarizationMiddleware (总结中间件): 它像是一个监控器,安插在 AI 的“思考”和“行动”之间,时刻盯着对话的长度。
  • model="gpt-4o-mini" (降级模型): 这是一个非常聪明的省钱策略。主任务用强大的 gpt-4o,但“总结对话”这种体力活交给更便宜、更快的 gpt-4o-mini,性价比极高。
  • trigger={"tokens": 4000} (触发阈值): 设定一条红线。当对话消耗的 Token 达到 4000 时,系统会自动执行压缩操作,防止内存溢出导致报错。
  • keep={"messages": 20} (滑动窗口): 在总结时,不会把所有信息都压缩掉。它会保留最近的 20 条对话,保证 AI 还能记得你刚刚说过什么,而更久远的内容则转化为摘要。

工作流程:

  • 监控对话长度,达到阈值时自动触发 系统会持续计算对话所占用的 Token 数量。在代码示例中,一旦达到 4000 tokens,总结机制就会像闹钟一样被激活。
  • 用经济模型总结早期对话内容 为了节省成本,系统不会调用昂贵的主模型(如 GPT-4o),而是启动一个更便宜、速度更快的“助理模型”(如 GPT-4o-mini)来阅读之前的琐碎对话。
  • 用摘要替换冗长历史,永久保存到状态中 助理模型将旧的对话提炼成一段精简的摘要(Summary)。这段摘要会替换掉那些已经被“删掉”的原始对话记录,并存入 Agent 的 State(状态) 中。
  • 保留近期对话供参考 系统不会把所有内容都变成摘要。它会根据配置(如 keep={"messages": 20}原封不动地保留最近的 20 条消息。这样可以确保 AI 在理解长远背景的同时,对你刚刚提到的细节依然有“秒回”的反应能力

消息管理是‘塞临时纸条’,而自动总结是‘永久修改会议记录’!

最佳实践:构建可靠智能体的关键要点

1. 从简入手 (Start Simple)

  • 核心逻辑:不要一上来就搞复杂的动态工作流。
  • 建议:先使用固定提示词(Prompt)\和*基础工具*。先确保 AI 能跑通最基本的业务闭环,再逐步添加动态判断和复杂功能。

2.逐步测试 (Iterative Testing)

部分核心代码:

1
2
3
4
5
6
7
8
9
# 第一阶段:基础版本
agent = create_agent(model="gpt-4o", tools=basic_tools)

# 第二阶段:添加一个功能测试
agent = create_agent(
model="gpt-4o",
tools=basic_tools,
middleware=[state_aware_prompt] # 先加一个中间件
)

代码解读

  • 第一阶段(基础版本):只定义模型和工具,这是为了验证 Agent 的基础能力
  • 第二阶段(添加测试):在原基础上增加了一个 middleware=[state_aware_prompt]

目的一次只增加一个变量。如果 Agent 出错,你可以立即判定是新加的这个中间件(状态感知)导致的问题,而不是工具或模型本身的问题。

3. 关注成本 (Cost Awareness)

针对不同的任务选择最合适的模型,以平衡性能与开支:

  • 短对话/简单总结:使用 gpt-4o-mini(低成本、高速度)。
  • 中等复杂度任务:使用 gpt-4o(标准全能模型)。
  • 复杂推理/代码编写:使用 claude-3-5-sonnet(当前行业公认的逻辑最强模型之一)。

4. 善用现成工具 (Leverage Existing Tools)

  • 核心逻辑:不要重复造轮子。
  • 建议:优先利用 LangChain 或 LangGraph 内置的成熟组件(如 SummarizationMiddleware)。这些工具已经处理好了并发、重试和 Token 限制等底层脏活。

5. 分清临时与永久 (Transient vs. Permanent)

这是理解 Agent 架构的深度所在:

  • 临时变化:指单次思考过程中生成的临时变量(只影响这一次回答)。
  • 永久变化:指存入 State(状态机) 或数据库的信息。这种变化会随着生命周期延续,影响 Agent 以后所有的行为。

总结:从“玩具”到“专业工具”的蜕变

1. 模型上下文 (Model Context)

  • 定义:控制 AI 的“思考内容”。
  • 解读:这通常指注入到 Prompt 中的即时信息。通过中间件,我们可以动态地根据用户意图,把最相关的背景资料、知识库内容喂给模型,确保它“想得对”、“不幻觉”。

2. 工具上下文 (Tool Context)

  • 定义:控制 AI 的“行动能力”。
  • 解读:对应你之前看过的代码(如权限校验)。它决定了 AI 在调用外部接口(发邮件、查数据库)时,是否具备必要的凭证(如工号、Token)以及操作权限。这确保了 AI “做得稳”。

3. 生命周期上下文 (Lifecycle Context)

  • 定义:控制工作“流程自动化”。
  • 解读:这涉及长时记忆和状态机管理(如自动总结、会话保持)。它确保 AI 能够跨越多个对话轮次,甚至跨越不同的任务阶段,依然记得“我是谁”、“我进行到哪一步了”。这确保了 AI “跟得住”。

核心价值总结

  • 摆脱演示环境(Demo):传统的 AI 往往只能在固定的、理想化的对话中表现良好。

  • 落地真实业务场景:通过系统性的上下文管理,让智能体能够:

    1. 真正理解业务需求:不是复读机,而是懂逻辑。
    2. 做出智能响应:根据当前状态和权限做出最优决策。
    3. 行为可靠:过程可控,结果可预测。