news 2026/9/12 12:17:31

LlamaIndex ReAct Agent 系统提示模板(System Header Template)深度解析与自定义指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LlamaIndex ReAct Agent 系统提示模板(System Header Template)深度解析与自定义指南

LlamaIndex ReAct Agent 系统提示模板(System Header Template)深度解析与自定义指南

【免费下载链接】llama_indexLlamaIndex is the document processing platform for AI项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index

导读

system_header_template.md是 LlamaIndex ReAct(Reasoning + Acting)Agent 的"系统提示"骨架,定义了 Agent 如何感知可用工具、如何组织 Thought / Action / Action Input 输出、以及何时以 Answer 收尾的完整行为协议。本文将以该模板文件为主体,结合 prompts.py、formatter.py、output_parser.py 与 react_agent.py 的源码实现,逐段拆解模板结构、占位符机制、上下文注入原理,并给出基于ReActChatFormatter的完整自定义实战方案。读完本文,你将理解 ReAct Agent 提示词从模板到最终 LLM 输入消息的完整流水线,并能够按需定制自己的系统提示模板。

一、模板文件在仓库中的位置与加载方式

该模板位于仓库路径 llama-index-core/llama_index/core/agent/react/templates/system_header_template.md,是 ReAct Agent 默认系统提示的唯一数据源。它并不是被静态引用的"文档",而是在模块导入时被程序化读取的运行时资源:

# llama-index-core/llama_index/core/agent/react/prompts.py with ( Path(__file__).parents[0] / Path("templates") / Path("system_header_template.md") ).open("r", encoding="utf-8") as f: __BASE_REACT_CHAT_SYSTEM_HEADER = f.read()

这段代码通过Path(__file__).parents[0] / "templates" / "system_header_template.md"定位模板文件(即prompts.py同级的templates/目录),读取全文后得到原始模板字符串。这意味着:

  • 模板以UTF-8 编码的 Markdown 文本形式参与运行时 prompt 构建;
  • 修改模板文件即可全局改变所有默认 ReAct Agent 的系统提示(仓库只读,实际使用中请通过代码自定义而非直接改文件);
  • 模板中的占位符{tool_desc}{tool_names}{context_prompt}在后续环节被替换为真实内容。

二、模板内容逐段拆解

模板全文由四个功能段落组成,每一段都对应 Agent 行为协议的一个关键约束:

1. 角色定位段

You are designed to help with a variety of tasks, from answering questions to providing summaries to other types of analyses.

这段定义了 Agent 的通用助手身份,不限定具体领域,为后续工具调用与多轮推理预留了开放性。在实际业务中,开发者通常会在自定义模板中将其替换为更聚焦的角色描述(例如"你是一名金融顾问")。

2. 工具使用说明段

## Tools You have access to a wide variety of tools. You are responsible for using the tools in any sequence you deem appropriate to complete the task at hand. This may require breaking the task into subtasks and using different tools to complete each subtask. You have access to the following tools: {tool_desc} {context_prompt}

这里出现两个关键占位符:

  • {tool_desc}:由 formatter.py 中的get_react_tool_descriptions()生成,对每个注册工具输出如下固定格式:

    > Tool Name: {tool.metadata.name} Tool Description: {tool.metadata.description} Tool Args: {tool.metadata.fn_schema_str}

    其中fn_schema_str是工具函数的 JSON Schema 字符串(即工具参数的类型签名),这保证了 LLM 能准确了解每个工具"叫什么、干什么、参数长什么样"。

  • {context_prompt}:上下文提示占位符。源码 prompts.py 基于原始模板派生了两个公开常量:

    • REACT_CHAT_SYSTEM_HEADER:将{context_prompt}替换为空字符串(replace("{context_prompt}", "", 1)),即无额外上下文的默认版本;

    • CONTEXT_REACT_CHAT_SYSTEM_HEADER:将{context_prompt}替换为一段带{context}占位符的上下文说明:

      Here is some context to help you answer the question and plan: {context}

    两者的选择逻辑见ReActChatFormatter.from_defaults():未提供context时使用前者,提供context时自动切换为后者,确保自定义系统提示(system prompt)能被注入到模板中。

3. 输出格式协议段(ReAct 循环的核心)

## Output Format Please answer in the same language as the question and use the following format: Thought: The current language of the user is: (user's language). I need to use a tool to help me answer the question. Action: tool name (one of {tool_names}) if using a tool. Action Input: the input to the tool, in a JSON format representing the kwargs (e.g. {{"input": "hello world", "num_beams": 5}}) Please ALWAYS start with a Thought. NEVER surround your response with markdown code markers. You may use code markers within your response if you need to. Please use a valid JSON format for the Action Input. Do NOT do this {{'input': 'hello world', 'num_beams': 5}}. If you include the "Action:" line, then you MUST include the "Action Input:" line too, even if the tool does not need kwargs, in that case you MUST use "Action Input: {{}}". If this format is used, the tool will respond in the following format: Observation: tool response You should keep repeating the above format till you have enough information to answer the question without using any more tools. At that point, you MUST respond in one of the following two formats: Thought: I can answer without using any more tools. I'll use the user's language to answer Answer: [your answer here (In the same language as the user's question)] Thought: I cannot answer the question with the provided tools. Answer: [your answer here (In the same language as the user's question)]

这是模板信息密度最高的部分,它定义了 ReAct 循环的完整状态机协议

  • 动作分支Thought:Action:(工具名,取值来自{tool_names})→Action Input:(必须为合法 JSON,单引号形式被明确禁止);
  • 观测回环:工具执行结果以Observation:形式返回,Agent 需循环"Thought → Action → Observation"直到信息充足;
  • 终止分支:信息充足或无法回答时,必须以Thought:+Answer:收尾;
  • 语言要求:必须使用与用户提问相同的语言回答;
  • 格式约束:必须以Thought:开头、禁止用 Markdown 代码块包裹输出、Action:出现则Action Input:必须同时出现(无参数时也必须给Action Input: {})。

这些协议并非仅停留在提示词层面——output_parser.py 用正则严格实现了同一套协议,构成"提示约束 + 解析校验"的双重保障。例如extract_tool_use()用正则(?:\s*Thought: (.*?)|(.+))\n+Action: ([^\n\(\) ]+).*?\n+Action Input: .*?(\{.*\})提取 Thought / Action / Action Input,而ReActOutputParser.parse()则按"Action 优先于 Answer"的规则(action_idx < answer_idx时优先解析为动作步骤)从 LLM 输出中判定当前步是"调用工具"还是"直接回答"。这意味着:模板怎么写,解析器就怎么读,两者必须保持一致。

4. 对话历史锚点段

## Current Conversation Below is the current conversation consisting of interleaving human and assistant messages.

模板末尾的## Current Conversation标题是给后续消息的"位置锚点",提示 LLM 在此标题之后是交替出现的用户与助手消息序列。实际运行时,formatter.py 会将模板渲染结果作为role=MessageRole.SYSTEM的首条消息,其后依次拼接chat_history与推理历史reasoning_history(推理步骤中ObservationReasoningStepMessageRole.USER角色呈现,其余以ASSISTANT角色呈现),从而形成完整的 LLM 输入消息列表。

三、模板如何被 ReAct Agent 使用:完整调用链

模板从静态文件到最终 LLM 输入,经历了如下调用链:

  1. prompts.py 读取模板文件,派生出REACT_CHAT_SYSTEM_HEADERCONTEXT_REACT_CHAT_SYSTEM_HEADER两个常量;
  2. formatter.py 的ReActChatFormattersystem_header为字段(默认值为REACT_CHAT_SYSTEM_HEADER),在format()中调用self.system_header.format(**format_args)完成占位符替换:tool_desc来自工具描述拼接,tool_names来自工具名逗号拼接,context在设置了self.context时注入;
  3. react_agent.py 的ReActAgent.take_step()调用formatter.format(tools, chat_history, current_reasoning)得到input_chat,交给 LLM;
  4. LLM 输出经 output_parser.py 的ReActOutputParser.parse()解析为ActionReasoningStep(继续调工具)或ResponseReasoningStep(终止并回答)。

值得注意的是,workflow 版 ReActAgent 还内置了模板自动切换逻辑:当设置了system_prompt时,model_validator会把system_prompt写入formatter.context,并检测当前system_header是否包含{context}占位符——若不含,则自动替换为CONTEXT_REACT_CHAT_SYSTEM_HEADER,保证自定义系统提示真正出现在系统消息中。这一行为在 test_prompt_customization.py 中有明确测试断言。

四、实战:自定义 ReAct 系统提示模板

掌握了模板结构与注入机制后,可以通过ReActChatFormatter进行三种层级的自定义。

方式一:注入上下文(system prompt)

这是最常见的用法——通过from_defaults(context=...)让模板自动切换为带{context}的版本:

from llama_index.core.agent.react.formatter import ReActChatFormatter formatter = ReActChatFormatter.from_defaults( context="You are a helpful financial advisor specializing in quarterly reports." ) # 此时 formatter.system_header 自动为 CONTEXT_REACT_CHAT_SYSTEM_HEADER # 渲染后系统消息中将包含 "Here is some context to help you answer the question and plan:\n{context}"

等价地,在使用 workflow 版ReActAgent时直接传system_prompt

from llama_index.core.agent.workflow import ReActAgent agent = ReActAgent(system_prompt="You are a helpful financial advisor.")

源码 react_agent.py 会自动完成 context 写入与模板切换。测试 test_prompt_customization.py 还验证了:当同时传入自定义 formatter 的contextsystem_prompt时,system_prompt会被前置拼接到已有 context 之前。

方式二:整体替换系统提示模板

如果你需要完全重写角色定义、工具说明或输出格式,可直接传入自定义system_header字符串(模板中必须保留{tool_desc}{tool_names}占位符,否则工具信息将无法注入):

from llama_index.core.agent.react.formatter import ReActChatFormatter custom_header = """\ You are a coding assistant. You must always use tools to answer. ## Tools {tool_desc} ## Output Format Always reply with: Thought: ... Action: one of {tool_names} Action Input: {{"arg": "value"}} ## Current Conversation """ formatter = ReActChatFormatter.from_defaults(system_header=custom_header)

方式三:通过update_prompts运行时更新

workflow 版ReActAgent将系统提示以react_header为键暴露给提示词更新接口(react_agent.py),可结合PromptTemplate做部分格式化:

from llama_index.core import PromptTemplate from llama_index.core.agent.workflow import ReActAgent from textwrap import dedent agent = ReActAgent() prompt = PromptTemplate( dedent( """\ Required template variables: {tool_desc} {tool_names} Additional variables: {dummy_var} """ ) ) agent.update_prompts({"react_header": prompt.partial_format(dummy_var="dummy_context")})

该用法在 test_prompt_customization.py 中有对应测试:部分格式化后的dummy_var会保留在agent.formatter.system_header中,说明update_prompts支持携带额外模板变量的部分格式化。

此外,ReActChatFormatter是普通 Pydantic 模型,可被继承重写(test_react_chat_formatter.py 展示了继承并重写format()的 Mock 形式),适合需要完全控制消息组装顺序的高级场景。

五、模板与输出解析器的契约关系(深入原理)

模板的"输出格式协议段"与 output_parser.py 的正则解析逻辑是一一对应的硬契约:

模板协议要求解析器实现(output_parser.py)
动作分支Thought: ...\nAction: <name>\nAction Input: <json>extract_tool_use()正则提取三元组,parse_action_reasoning_step()dirtyjson(宽松 JSON 解析)解析 Action Input
终止分支Thought: ...\nAnswer: <answer>extract_final_response()用正则\s*Thought:(.*?)Answer:(.*?)(?:$)提取最终答案
必须以Thought:开头ReActOutputParser.parse()re.search(r"Thought:", output, re.MULTILINE)定位起始
未按格式输出时的兜底三个关键字(Thought/Action/Answer)都未命中时,将整段输出视为隐式回答((Implicit) I can answer without any more tools!

解析器还体现了两个与模板呼应的设计细节:

  1. Action 优先于 Answer:当输出同时包含Action:Answer:时,按位置先后判断(action_idx < answer_idx则走动作分支),防止模型在调工具的同时试图结束对话;
  2. 弱模型容错:注释明确说明较弱的 LLM 可能生成糟糕的 Action Input JSON,因此先用dirtyjson解析,失败后再回退到正则化的action_input_parser()(output_parser.py)。

也就是说,如果你自定义模板修改了输出协议,必须同步重写或扩展ReActOutputParser,否则解析器将无法从新格式中提取工具调用与最终答案。这是自定义 ReAct 提示词时最容易踩的坑。

六、与 workflow 版 ReActAgent 的集成要点

在基于 Workflow 的新版 ReAct Agent(react_agent.py)中,模板相关的集成要点可归纳为:

  • formatterReActAgent的 Pydantic 字段,默认工厂default_formatter()会读取system_prompt并调用ReActChatFormatter.from_defaults(context=...)
  • take_step()每轮都会基于ctx.store中缓存的current_reasoning(推理步骤列表)重新格式化输入,因此模板注入发生在每一轮,而不是只在首轮;
  • 当 LLM 返回空内容或解析失败时,Agent 会构造携带"格式纠正"提示的retry_messages回传给 LLM,这些纠正提示同样复用了模板中定义的两种输出格式(工具调用格式 / 直接回答格式),可见模板协议在容错路径上也被一致遵循(react_agent.py);
  • 工具执行结果通过ObservationReasoningStep追加进current_reasoning,并在下一轮以 USER 角色回填到消息列表,与模板"重复循环直到信息充足"的指令闭环吻合。

七、总结与最佳实践

system_header_template.md虽然只是一份 Markdown 文本,却是 LlamaIndex ReAct Agent 提示工程的"总纲"。结合源码可以提炼出以下实践建议:

  1. 保持输出协议不变,只改角色与上下文:绝大多数业务定制(领域角色、背景知识、回答风格)通过context/system_prompt注入即可,无需改动输出格式段,避免与默认解析器失配;
  2. 如需整体替换模板,务必保留{tool_desc}{tool_names}占位符,并同步定制ReActOutputParser,确保"提示约束"与"解析校验"两条链路一致;
  3. 善用update_prompts+PromptTemplate:它支持部分格式化携带额外变量,是实现"多 Agent 共享模板 + 差异化参数"的轻量手段;
  4. 关注模板与容错机制的联动:默认的格式纠正消息(retry_messages)假定模型遵循模板中的两种输出格式,自定义时需评估容错路径是否仍然成立;
  5. 以测试为行为基准:仓库中 test_react_chat_formatter.py 与 test_prompt_customization.py 完整覆盖了 formatter 继承、context 注入、模板自动切换与部分格式化等关键行为,是验证自定义模板是否符合预期的现成参考。

理解这份模板及其背后的实现,就等于掌握了 LlamaIndex ReAct Agent 提示工程的核心入口——从"模型知道有哪些工具"到"模型以什么格式调用工具"再到"模型何时停止调用并作答",全部由这一份系统提示骨架所驱动。

【免费下载链接】llama_indexLlamaIndex is the document processing platform for AI项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 12:16:51

Godot 4环境可信度构建指南:安装、汉化与首个2D场景

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 12:16:19

基于Flink的流式RAG架构实现实时知识增强

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 12:14:58

Spring Boot与Spring Cloud版本选型实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 12:12:22

LlamaIndex工作流:构建高效RAG系统的核心技术解析

1. LlamaIndex工作流核心概念解析LlamaIndex作为当前最热门的AI数据编排框架&#xff0c;其Workflow模块正在彻底改变我们构建复杂RAG&#xff08;检索增强生成&#xff09;系统的方式。不同于传统脚本的线性执行模式&#xff0c;工作流将LLM应用的各个环节封装为可复用的标准化…

作者头像 李华
网站建设 2026/9/12 12:11:56

车载Android USB开发:从即插即用到车规级确定性通信

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 12:10:34

高效调试方法论:从BUG定位到性能优化

1. 调试基础&#xff1a;从认知BUG到工具选择每个程序员都经历过这样的时刻&#xff1a;代码运行结果与预期不符&#xff0c;控制台抛出莫名其妙的错误&#xff0c;或是功能在测试环境正常却在生产环境崩溃。这些我们统称为BUG——程序世界里的不速之客。但真正区分普通开发者和…

作者头像 李华