# LLM工程化:提示工程、RAG、Agent与结构化输出实战
## 1. 背景:从“聊天”到“生产级组件”的鸿沟
2024年以来,GPT-4o、Claude 3.5 Sonnet等模型在对话、代码生成上表现出众,但当开发人员试图将LLM集成到生产系统时,很快发现:**仅靠一条“Chat: ”指令远远不够**。
典型痛点包括:
- **幻觉**:模型回答脱离事实,尤其在缺少检索上下文时。
- **输出不可解析**:返回自由文本,下游无法用代码处理。
- **无工具调用能力**:模型无法查询数据库、执行API、发送邮件。
- **行为不可复制**:同样的输入在不同请求下结果不一致。
根源在于:生产级AI系统需要将LLM变成**可编程、可评估、可部署的软件组件**,而不仅仅是聊天机器人。这催生了现代Prompt Engineering的四个核心支柱:**系统提示(System Prompt)、RAG上下文注入、结构化输出(Structured Outputs)和Agent编排**。
截至2026年6月,主流框架(LangChain v0.3.14、OpenAI SDK v1.56、Pydantic v2.9)已将上述能力标准化。本文将以实际代码演示如何组合这些技术,构建生产就绪的LLM应用。
## 2. 技术架构:四层协同的AI工程模型
一个可靠的LLM应用通常包含以下层次:
| 层次 | 职责 | 关键组件 |
|------|------|----------|
| 系统提示层 | 定义模型角色、约束、行为红线 | 角色描述、禁止事项、输出规则 |
| 上下文层 | 注入外部知识减少幻觉 | RAG检索器、文档分块、重排序 |
| 结构与工具层 | 强制输出格式、暴露函数接口 | JSON Schema、Tool Definition |
| 编排层 | 多步推理、条件跳转、工具调用循环 | Agent循环、记忆、错误重试 |
### 2.1 系统提示:LLM的“宪法”
系统提示是每次请求都附加的指令块。它定义了模型“是什么”、“做什么”、“不能做什么”。好的系统提示应包含:
- **角色与任务**:例如“你是客户支持助手,基于文档回答”。
- **上下文注入位置**:通常用`{context}`占位符,由RAG填充。
- **输出约束**:如“如果信息不足,回答‘我不知道’”。
- **引用要求**:强制输出时附带来源文档名称。
### 2.2 RAG:让模型“知道”而非“猜对”
RAG(Retrieval-Augmented Generation)通过外部知识库注入事实。2026年,主流做法是:
1. 文档分块(chunk_size=512 tokens,overlap=20%)
2. 向量化(text-embedding-3-large,维度3072)
3. 检索(Top-K=5,使用Cohere重排序)
4. 注入到系统提示的`{retrieved_context}`位置
### 2.3 结构化输出:从“文本”到“数据”
OpenAI从2025年11月开始提供`structured_outputs=true`参数,直接返回符合JSON Schema的响应。这避免了传统“先用LLM生成文本再用正则解析”的脆弱方案。Claude 3.5同样支持`tools`模式定义输出结构。
### 2.4 Agent编排:多步推理与工具调用
Agent将LLM作为“大脑”,配合工具(如数据库查询、计算器、邮件API)执行复杂任务。典型的ReAct循环包括:思考→行动→观察→思考……直到完成。
## 3. 实践:从简单提示到生产级Agent
### 3.1 基础RAG系统提示模板
以下代码展示了使用OpenAI Python SDK v1.56构建一个带有RAG上下文的客服助手。注意系统提示中使用`{company_name}`和`{context}`占位符,并通过`messages`结构注入。
```python
import openai # v1.56.0
from typing import List
def build_rag_messages(
company_name: str,
retrieved_docs: List[str],
user_question: str
):
# 组装检索到的文档
context = "\n---\n".join(
[f"Source: {doc['source']}\n{doc['content']}"
for doc in retrieved_docs]
)
system_prompt = f"""You are a helpful support assistant for {company_name}.
Answer questions using only the documentation provided below.
If the documentation does not contain sufficient information to answer the question,
respond: "I don't have enough information from the available documentation to answer this question."
Always cite the source document name at the end of your answer.
[CONTEXT — Retrieved documentation]
{context}"""
return [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_question}
]
# 实际调用
response = openai.chat.completions.create(
model="gpt-4o", # 或 gpt-4o-2026-05
messages=build_rag_messages(
company_name="Acme Corp",
retrieved_docs=[{...}],
user_question="How to reset password?"
),
temperature=0.0,
max_tokens=512
)
```
### 3.2 结构化输出:从邮件中提取字段
生产场景中,常常需要从非结构化输入中提取结构化数据。以下代码利用Pydantic v2.9定义Schema,并通过OpenAI的`response_format`参数强制输出JSON。
```python
from pydantic import BaseModel, Field # v2.9.0
import openai
class EmailExtract(BaseModel):
sender_name: str = Field(description="Name of the person sending the email")
company: str = Field(description="Company name")
team_size: int = Field(description="Number of team members")
deadline: str = Field(description="Deadline date (format: YYYY-MM-DD)")
budget: str = Field(description="Budget amount and currency")
contact_email: str = Field(description="Contact email address")
# 使用结构化输出(OpenAI v1.56+)
def extract_email_info(email_text: str) -> EmailExtract:
response = openai.beta.chat.completions.parse(
model="gpt-4o",
messages=[
{"role": "system", "content": "Extract fields from the email and return as structured JSON."},
{"role": "user", "content": email_text}
],
response_format=EmailExtract, # OpenAI自动转换为JSON Schema
temperature=0.0
)
return response.choices[0].message.parsed # 直接返回Pydantic对象
# 测试
email = """
Hi, I'm Sarah from Acme Corp. We need a data analytics platform for our team of 12 by September 2026. Budget: ₹8 lakhs. Please contact sarah@acme.co
"""
result = extract_email_info(email)
print(result.model_dump_json(indent=2))
# 输出: {"sender_name":"Sarah","company":"Acme Corp","team_size":12,...}
```
**关键数据**:在LangSmith的基准测试中,使用`response_format`的结构化输出比传统`temperature=0 + 正则解析`模式,字段提取准确率从76%提升至99.4%,且解析耗时降低50%。
### 3.3 Agent编排:结合RAG与工具
真实场景往往需要将以上技术组合。例如一个“销售线索生成Agent”:收到邮件后,先调用结构化提取,再RAG查询公司背景,然后调用CRM API创建记录。以下是使用LangChain v0.3.14的简化实现。
```python
from langchain_openai import ChatOpenAI # v0.3.14
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain.tools import tool
from langchain.memory import ConversationBufferMemory
@tool
def search_company_info(company_name: str) -> str:
"""搜索公司信息(模拟RAG)"""
return f"Contoso: AI startup, 50 employees, founded 2022"
@tool
def create_crm_lead(name: str, company: str, email: str) -> str:
"""在CRM中创建销售线索"""
# 实际调用CRM API
return f"Lead created: {name} from {company}"
llm = ChatOpenAI(model="gpt-4o", temperature=0.0)
agent = create_tool_calling_agent(
llm=llm,
tools=[search_company_info, create_crm_lead],
system_message="你是销售线索处理助手。首先从邮件中提取字段,然后搜索公司信息,最后创建CRM线索。按步骤执行。"
)
agent_executor = AgentExecutor(agent=agent, tools=[search_company_info, create_crm_lead], verbose=True)
# 运行
agent_executor.invoke({"input": email})
# 可见到多步推理与工具调用
```
## 4. 总结与展望
从2024到2026年,LLM应用开发已经从“写提示”进化到“编排系统”。核心三点:
- **结构化**:用Schema代替自然语言输出,使结果可编程。
- **可评估**:每个组件(RAG召回、工具调用、输出格式)均应有自动化评估。
- **可部署**:利用LangChain等框架将提示、RAG、Agent封装为模块,便于CI/CD。
未来趋势:**多模型协同**(如用小模型做路由、大模型做推理)和**自修复Agent**(Agent检错后自动重试)将进一步降低幻觉风险。对于工程师,掌握上述四层技术栈,是构建可靠LLM产品的必修课。
**参考**:本文示例代码兼容OpenAI API 2025-11以后版本、LangChain v0.3.14、Pydantic v2.9。建议在LangSmith平台上进行生产级评估与监控。