如果你想做大模型落地,最容易走偏的地方不是"模型选错",而是形态选错 :
Chat 能搞定的事情你上 Agent,RAG 该上的地方你用 Prompt 硬编,最后就是维护成本爆炸 + 效果还不稳。
这篇只给你两样东西:
- 一张选型表(照着选不容易翻车)
- 三段最小 Python 骨架(直接开工)
1)选型表(先判断"证据"和"动作")
| 形态 | 你要解决什么 | 什么时候用 | 你需要准备什么 | 上线复杂度 |
|---|---|---|---|---|
| Chat | 生成/总结/解释/问答 | 不需要引用内部资料、不需要执行动作 | 几乎无 | 低 |
| RAG | 基于资料回答 + 可追溯 | 必须基于文档/知识库回答,且希望可引用来源 | 文档治理 + 检索链路 | 中 |
| Agent | 规划 + 多步执行 | 需要调用工具/接口跑流程、自动化任务 | 工具接口 + 权限 + 日志 + 回退 | 高 |
一句话判断:
- 要证据 → RAG
- 要动作 → Agent
- 都不要 → Chat
2)统一一个"接入层"(可迁移写法)
很多团队后面都会做:多模型对比、路由、评测。
因此我建议把 LLM 调用封装成一个"接入层",用 OpenAI 兼容协议会省事(多数情况下只改 base_url/api_key)。
以 OpenAI 兼容服务147ai 为例(参数以文档与控制台为准):
- Base URL:
https://147ai.com/v1 - 端点:
POST /chat/completions - 鉴权:
Authorization: Bearer <KEY>
2.1 我建议你按"工程文件"拆开(后续扩展会很顺)
一个很常见的翻车点是:一开始把所有逻辑塞在一个脚本里,等到要加 RAG/评测/路由时,没人敢改。
你可以用这个最小目录结构开局:
text
app/
llm_client.py # 统一入口:chat()、超时、重试、日志
prompts.py # 系统提示词/模板集中管理
rag.py # retrieve()、build_context()、rag_answer()
agent.py # 工具注册、停止条件、run_agent()
eval.py # 最小评测:样例集+指标
3)Chat:最小可用(可直接跑)
bash
pip install -U openai
python
from openai import OpenAI
client = OpenAI(
api_key="YOUR_147AI_API_KEY",
base_url="https://147ai.com/v1",
)
def chat(prompt: str) -> str:
resp = client.chat.completions.create(
model="gpt-4.1-mini", # 换成控制台支持的模型全名
messages=[{"role": "user", "content": prompt}],
)
return resp.choices[0].message.content
print(chat("把下面这段需求拆成任务清单,并给验收标准:..."))
3.1 把"重试/日志"先写进接入层(上线前最省你命)
哪怕你现在只是 PoC,也建议把这两件事在接入层就写好:
- 重试:应对偶发网络/网关抖动
- 日志:定位"为什么这次不行"
下面是一个不引入第三方依赖的"最小重试"示例(你可以移到 llm_client.py):
python
import time
from openai import OpenAI
client = OpenAI(api_key="YOUR_147AI_API_KEY", base_url="https://147ai.com/v1")
def chat_with_retry(prompt: str, retries: int = 2, backoff: float = 0.8) -> str:
last_err = None
for i in range(retries + 1):
try:
resp = client.chat.completions.create(
model="gpt-4.1-mini",
messages=[{"role": "user", "content": prompt}],
)
return resp.choices[0].message.content
except Exception as e:
last_err = e
print(f"[retry] attempt={i+1} err={e}")
time.sleep(backoff * (2 ** i))
raise last_err
4)RAG:最小链路(能跑通就行,先别追求完美)
RAG 的本质:检索(找证据) + 生成(写答案)。
python
def retrieve(query: str) -> list[str]:
# TODO: 向量化 -> top-k 检索 ->(可选)重排
return ["chunk1", "chunk2"]
def rag(query: str) -> str:
context = "\n\n".join(retrieve(query))
prompt = f"""你是企业知识助手。
请只基于<资料>回答;如果资料不足,请回答"资料不足"。
<资料>
{context}
</资料>
问题:{query}
"""
return chat(prompt)
print(rag("我们的退款规则是什么?需要引用原文。"))
RAG 最常见翻车点:chunk 切得不对、检索不到、检索到错的、拼接太长污染提示词。
建议下一步做:评测集(30--100条)+ 检索质量指标。
4.1 RAG 真的"难"在哪:不是生成,是检索
RAG 的正确打开方式是两层评测:
- 先评检索:Top-k 里能不能命中正确段落(命中率/召回率)
- 再评生成:答案是否"只基于资料",引用是否正确
否则你会出现一种典型错觉:模型很强,但"答非所问"。其实是检索没命中,模型只能瞎编。
4.2 先把向量库抽象成接口(方便替换)
python
class VectorStore:
def search(self, query: str, k: int = 5) -> list[str]:
# TODO: 返回最相关的chunk文本(或带source信息)
return []
store = VectorStore()
def retrieve(query: str) -> list[str]:
return store.search(query, k=5)
4.3 一个更"生产友好"的 RAG 提示词(避免资料不足也硬答)
text
你是企业知识助手。
规则:
1) 只允许基于<资料>回答;
2) 如果资料不足以支持结论,请回答"资料不足",并说明还缺哪类资料;
3) 回答末尾列出引用的资料片段序号(如[1][2])。
5)Agent:最小循环(先把"停止条件"写清楚)
Agent 的本质:LLM 负责规划,工具负责执行 。
你一定要写清楚 3 个"护栏":最大步数、超时、关键动作确认。
python
MAX_STEPS = 6
def tool_search_kb(q: str) -> str:
return "..."
def tool_create_ticket(title: str, detail: str) -> str:
return "ticket_id=..."
def run_agent(task: str) -> str:
# 这里只给"工程骨架",具体工具调用格式按你使用的平台/SDK 为准
messages = [{"role": "user", "content": task}]
for _ in range(MAX_STEPS):
# 1) 让模型输出下一步计划(或工具调用)
# 2) 执行工具
# 3) 把结果写回 messages
pass
return "stopped"
5.1 Agent 护栏清单(写进代码,不要只写在文档里)
- MAX_STEPS:防循环
- 超时:防卡死(尤其是工具响应慢)
- 关键动作确认:比如"发通知/改状态/生成订单"必须二次确认
- 最小权限:工具只暴露必要参数,避免越权
- 审计日志:每步输入输出、工具名、参数、结果、耗时
5.2 用"工具白名单"限制模型乱调用
python
ALLOWED_TOOLS = {"search_kb", "create_ticket"}
tools = {
"search_kb": tool_search_kb,
"create_ticket": tool_create_ticket,
}
def safe_call_tool(name: str, *args, **kwargs):
if name not in ALLOWED_TOOLS:
raise ValueError(f"tool not allowed: {name}")
return tools[name](*args, **kwargs)
6)下一篇你想看哪个?
- RAG 的 10 个翻车点(含分块/检索/重排/评测清单)
- 把调用做成可上线:超时/重试/限流/日志怎么做
- 多模型对比评测表:一周把"该选哪个模型"说清楚
声明
本文以技术分享为主;示例参数以对应文档与控制台为准,不构成购买建议。
147ai 仅作为示例入口:147ai 官网