Chat / RAG / Agent 最小实现模板:一张选型表 + 三段 Python 骨架

如果你想做大模型落地,最容易走偏的地方不是"模型选错",而是形态选错

Chat 能搞定的事情你上 Agent,RAG 该上的地方你用 Prompt 硬编,最后就是维护成本爆炸 + 效果还不稳。

这篇只给你两样东西:

  1. 一张选型表(照着选不容易翻车)
  2. 三段最小 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 的正确打开方式是两层评测:

  1. 先评检索:Top-k 里能不能命中正确段落(命中率/召回率)
  2. 再评生成:答案是否"只基于资料",引用是否正确

否则你会出现一种典型错觉:模型很强,但"答非所问"。其实是检索没命中,模型只能瞎编。

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)下一篇你想看哪个?

  1. RAG 的 10 个翻车点(含分块/检索/重排/评测清单)
  2. 把调用做成可上线:超时/重试/限流/日志怎么做
  3. 多模型对比评测表:一周把"该选哪个模型"说清楚

声明

本文以技术分享为主;示例参数以对应文档与控制台为准,不构成购买建议。

147ai 仅作为示例入口:147ai 官网

相关推荐
Hilaku3 小时前
当 Gemini 3 能写出完美 CSS 时,前端工程师剩下的核心竞争力是什么?
前端·javascript·ai编程
xuedaobian6 小时前
2025年我是怎么用AI写代码的
前端·程序员·ai编程
熊猫钓鱼>_>6 小时前
GLM4.6多工具协同开发实践:AI构建智能任务管理系统的完整指南
人工智能·python·状态模式·ai编程·glm·分类系统·开发架构
知了一笑6 小时前
2025年AI写产品的那些事
ai·ai编程·独立开发
glumes9 小时前
使用 Cursor 进行 AI 编程的年度总结
ai编程
AI产品库9 小时前
通义灵码是什么?阿里云推出的智能编程助手全面评测-AI产品库
人工智能·ai编程
程序员码歌10 小时前
短思考第267天,周末亲子游,拆解一个很常见的商业化项目!
ai编程·全栈·创业
qiyue7710 小时前
AI浪潮下,前端的路在何方,附前端转KMP实践
前端·ai编程
我要改名叫嘟嘟10 小时前
2025年终总结(1),几乎都关于AI的工作
ai编程