最近身边不少朋友在讨论一个现象:各类大模型助手越来越强,但真要放到具体行业里用,总会卡在“能聊但不能干活”这一步。尤其是地产行业,置业顾问、客研、策划、运营手头都堆着数据,却很难让 AI 直接输出可用的结果。这个背景下,Harness成了 AI 工程化里被反复提到的关键词,而像CI Buddy这样面向地产人的专属智能助手路线,也开始被越来越多团队尝试。
本文将围绕“Harness 为什么火”和“如何为地产人设计一条专属的 CI Buddy 落地路线”展开,从概念拆解、架构设计、可运行的最小实现,到常见踩坑和工程化建议,完整梳理一遍。无论你是后端工程师、AI 应用开发者,还是地产行业数字化转型的技术负责人,都可以按本文的思路落地一套自己的 AI 助手。
1. Harness 概念拆解:大模型时代的执行框架
1.1 为什么都在谈 Harness
很多开发者最初看到Harness这个词,会误以为是 CI/CD 领域的 Harness 平台。实际上,在大模型和 AI Agent 爆发的背景下,Harness有了另一层更热门的含义:为大模型智能体设计的执行框架、工具编排层和运行控制层。
通俗地说,大模型本身就是一个“大脑”,擅长理解和生成文本,但它本身不会查询数据库、不会调用内部接口、不会自动发送邮件。如果我们想让 AI 完成“查看某楼盘本周来访量并生成分析简报”这样一条完整任务,就需要给大模型配上工具、流程、权限和校验规则。这套东西组合在一起,就是Harness。
再深入一点,Harness Engineering强调的是:把大模型的生成能力,嵌入到可控、可追踪、可回滚的业务执行环境里。它不是简单地调用一次 API,而是把一次对话拆成“理解意图 → 选择工具 → 执行工具 → 汇总结果 → 人工确认”这样的完整链路。
1.2 Harness 解决的核心问题
如果没有 Harness,直接让大模型去干活,通常会出现三个问题:
- 权限失控:模型可能读取到不该读的数据,甚至捏造不存在的字段。
- 工具调用不稳定:模型不知道该调哪个接口,或者在参数上反复出错。
- 结果不可追踪:一次生成结果无法沉淀为可复现的工作流,出了问题也很难定位。
Harness 的价值,就是把上面的“黑盒”变成“白盒”。它通过工具注册表、参数校验、流程编排、审批介入、日志追踪,让 AI 的能力在一个清晰的框架内发挥作用。
1.3 Harness 不是 Agent 本身
这里要区分两个概念:
- Agent(智能体):负责决策和生成,核心是“怎么想”。
- Harness(执行框架):负责约束和落地,核心是“怎么干”。
一个 Agent 可以在 Harness 内运行多个工具,也可以被多个 Harness 共用。很多团队之所以落地失败,就是因为把精力全部放在 Prompt 调优上,忽略了执行框架,导致模型输出得很好,但实际动作全是错的。
2. CI Buddy 是什么:地产人的专属 AI 工作台
2.1 从行业痛点出发
地产行业的数据链路非常长:前端有投拓、客研、营销,中间有案场管理、客户跟进,后端有签约、回款、运营。传统软件把数据录进了系统,但业务人员每天仍然要花大量时间查数据、做报表、写周报、整理客户跟进记录。
CI Buddy可以理解为为地产从业者设计的 AI 助手应用层。CI 可以拆成Customer Intelligence(客户智能),也可以理解为Construction Industry(建筑与地产行业)。Buddy 则意味着它不是一个冷冰冰的报表工具,而是一个能理解业务语义、主动辅助工作的“搭档”。
它和通用 AI 助手的区别在于:
- 知识范围聚焦:内置地产专业术语、政策规范、楼盘数据、产品户型等结构化信息。
- 动作链路闭环:不止回答“这个项目的容积率是多少”,还能触发“导出客户分析表”这样的动作。
- 权限边界清晰:不同角色看到的数据和能执行的操作不一样。
- 结果可见可控:所有生成内容都有来源,不允许模型随意发挥敏感数据。
2.2 CI Buddy 的典型使用场景
从实际落地角度来看,CI Buddy 的典型场景包括以下六类:
| 场景 | 使用角色 | 原来的痛点 | CI Buddy 能做什么 |
|---|---|---|---|
| 楼盘信息问答 | 置业顾问 | 项目资料分散在 PPT、Excel、系统里,很难快速找到 | 统一知识库,一问即答 |
| 客户跟进摘要 | 销售主管 | 客户沟通记录长,看不过来 | 自动提炼跟进重点和风险客户 |
| 周报/月报生成 | 项目运营 | 每周花几小时汇总数据、写文字 | 从数据源拉取指标,自动生成初稿 |
| 营销文案草稿 | 策划人员 | 写推文和海报文案费时 | 基于项目卖点生成多版本文案 |
| 市场政策问答 | 客研分析师 | 政策文件多,查询效率低 | 结构化政策库 + 语义检索 |
| 审批辅助 | 案场经理 | 折扣、调价、费用审批需要翻系统 | 快速汇总审批所需上下文 |
2.3 CI Buddy 的落地路线
一条清晰的CI Buddy 路线,可以拆成五个阶段:
- 场景选择题:先明确最痛的一个或两个场景,不要一上来做全能助手。
- 数据治理:把楼盘字典、客户表、周报模板、政策文件统一成模型可用的数据结构。
- Harness 搭建:实现工具注册、意图路由、参数校验和权限控制。
- 界面接入:在企业微信、钉钉、Web 工作台或企微机器人中接入入口。
- 灰度迭代:选定一个小团队试用,收集反馈后再扩大范围。
这条路线里,最容易忽略的是第 3 步。很多团队直接用大模型 API 做对话,结果功能看起来像“高级客服”,永远没有落地到业务流程里。
3. CI Buddy 整体架构设计
3.1 分层设计
为了让 CI Buddy 具备可扩展性,我推荐采用四层架构:
用户层:Web 工作台 / 企业微信机器人 / 钉钉应用 / 移动端 H5 ↓ 接入层:用户认证、会话管理、敏感词过滤、权限校验 ↓ Harness 层:意图识别 → 工具选择 → 参数解析 → 执行调度 → 结果校验 ↓ 数据层:楼盘字典、客户库、房源表、营销素材库、政策文件库其中 Harness 层是整个系统的核心,它决定了 AI 的能力边界。
3.2 Harness 层的关键模块
一个工程上可用的 Harness,至少要包含以下模块:
- 工具注册中心:把已有的内部接口封装成标准工具,每个工具包含名称、描述、入参结构、返回结构、调用地址和风险等级。
- 意图路由:根据用户的输入,判断要调用哪个工具。可以基于大模型,也可以基于规则或向量检索。
- 参数填充与校验:把自然语言中的信息映射成工具所需的参数,并做必填项和格式校验。
- 执行与拦截:调用工具,并在执行前做权限、数据范围、敏感操作拦截。
- 结果组装:把工具返回的 JSON 组装成用户可读的文本,必要时附上数据来源。
- 全链路日志:记录输入、意图、工具、参数、返回值、耗时,便于排查。
3.3 为什么不建议“一把梭”调大模型
有一种做法是把所有工具描述写进一个 System Prompt,让大模型自己决定怎么调。这种方式在演示时可以跑通,但在生产环境很容易出问题:
- 上下文过长导致 Token 消耗高;
- 工具一多,模型经常选错工具;
- 参数错误后没有重试机制;
- 敏感工具可能被越权调用。
所以,更稳妥的做法是:用轻量规则或提示词先做第一层路由,再用大模型做小范围内的语义理解。换句话说,把“选择执行路径”这种确定性逻辑交给代码,把“理解用户表述”这种不确定性逻辑交给大模型。
4. 最小可运行实现:为地产场景搭建一个 CI Buddy 核心
接下来我们写一个最小可运行的 Harness 实现,演示 CI Buddy 的核心逻辑。这个例子不依赖外部大模型 API,也能跑通“意图识别 → 工具调用 → 结果返回”的完整链路,方便你理解原理。实际项目中,把其中的规则匹配替换成大模型接口即可。
4.1 项目结构
建议按下面结构组织项目:
ci-buddy-demo/ ├── app.py # 入口,提供命令行调用方式 ├── harness.py # Harness 核心调度 ├── tools.py # 工具注册与实现 ├── config.py # 配置信息 ├── data/ │ ├── projects.json # 楼盘字典 │ └── customers.json # 客户跟进数据(脱敏) └── requirements.txt4.2 工具层实现
先看tools.py。每个工具都是一个标准的 Python 函数,并带有 schema 描述,方便 Harness 做路由。
# 文件路径:ci-buddy-demo/tools.py """ 工具层:这里是 CI Buddy 能够执行动作的地方。 实际项目中,可以把函数内部改为调用外部 HTTP API、 数据库查询或 RPA 脚本。 """ import json import os from datetime import datetime DATA_DIR = os.path.join(os.path.dirname(__file__), "data") def _load_json(filename: str): """加载 data 目录下的 JSON 文件,便于演示。""" file_path = os.path.join(DATA_DIR, filename) if not os.path.exists(file_path): return [] with open(file_path, "r", encoding="utf-8") as f: return json.load(f) def get_property_info(project_name: str) -> dict: """ 查询楼盘基础信息。 模拟场景:根据项目名称查询本地楼盘字典。 """ projects = _load_json("projects.json") for proj in projects: if proj["name"] == project_name: return { "ok": True, "data": proj, "message": f"已找到项目:{project_name}", } return { "ok": False, "data": None, "message": f"未找到项目:{project_name},请检查名称是否正确。", } def get_customer_week_report() -> dict: """ 生成本周客户跟进摘要。 模拟场景:读取客户数据,按本周时间汇总。 """ customers = _load_json("customers.json") week_start = "2025-06-09" # 示例日期,实际项目可由服务端计算 week_end = "2025-06-15" followed = [ c for c in customers if week_start <= c.get("last_follow_time", "") <= week_end ] high_intent = [c for c in followed if c.get("intent_level") in ("A", "B")] summary = { "date_range": f"{week_start} 至 {week_end}", "total_followed": len(followed), "high_intent_count": len(high_intent), "high_intent_customers": [ {"name": c["name"], "project": c["project"], "note": c.get("note", "")} for c in high_intent ], } return { "ok": True, "data": summary, "message": "本周客户跟进摘要已生成。", } def generate_marketing_copy(topic: str, style: str = "朋友圈") -> dict: """ 生成营销文案草稿。 演示模式下返回一段模板文案,实际项目可接入大模型生成。 """ template = f"【{style}】{topic},欢迎咨询详情,更多优惠等你解锁!" return { "ok": True, "data": {"topic": topic, "style": style, "copy": template}, "message": "文案草稿已生成。", } def search_policy(keyword: str) -> dict: """ 搜索政策文件中的关键词。 演示:返回本地静态政策摘要。 """ policy_lib = [ {"keyword": "公积金", "summary": "公积金贷款额度按最新政策执行。"}, {"keyword": "限购", "summary": "限购政策以区域最新通知为准。"}, {"keyword": "契税", "summary": "首套房契税优惠税率按 1% 执行。"}, ] result = [] for item in policy_lib: if keyword in item["keyword"] or keyword in item["summary"]: result.append(item) if not result: result = [{"keyword": keyword, "summary": "暂无匹配政策摘要,请人工确认。"}] return { "ok": True, "data": result, "message": f"政策关键词“{keyword}”检索完成。", }4.3 Harness 核心调度
harness.py是 Harness 层的关键。它的职责是:
- 维护工具注册表;
- 根据用户输入判断意图;
- 填充参数;
- 执行前检查权限;
- 返回统一封装的结果。
这里先做一个纯规则版本。它不会真正调用大模型,但每一步都有日志输出,方便看到 Harness 的工作过程。
# 文件路径:ci-buddy-demo/harness.py """ Harness 核心:负责工具注册、意图识别、参数填充、权限拦截。 """ import json import re import uuid from datetime import datetime from tools import ( get_property_info, get_customer_week_report, generate_marketing_copy, search_policy, ) class Harness: def __init__(self, user_role: str = "guest"): self.user_role = user_role self.logs = [] # 工具注册表 self.tools = { "property_info": { "name": "get_property_info", "description": "查询楼盘基础信息,需要传入项目名称。", "func": get_property_info, "required_params": ["project_name"], "roles": ["sales", "manager", "admin"], "risk": "low", }, "customer_week_report": { "name": "get_customer_week_report", "description": "生成本周客户跟进摘要。", "func": get_customer_week_report, "required_params": [], "roles": ["manager", "admin"], "risk": "medium", }, "marketing_copy": { "name": "generate_marketing_copy", "description": "生成营销文案草稿。", "func": generate_marketing_copy, "required_params": ["topic"], "roles": ["sales", "manager", "admin", "marketing"], "risk": "low", }, "policy_search": { "name": "search_policy", "description": "搜索政策文件关键词。", "func": search_policy, "required_params": ["keyword"], "roles": ["sales", "manager", "admin", "marketing", "analysis"], "risk": "low", }, } # 简单意图规则 self.intent_rules = [ { "intent": "property_info", "patterns": ["楼盘", "项目", "容积率", "户型", "项目信息"], "param_hints": ["project_name"], }, { "intent": "customer_week_report", "patterns": ["周报", "客户跟进", "本周客户", "跟进摘要"], "param_hints": [], }, { "intent": "marketing_copy", "patterns": ["文案", "推文", "广告语", "朋友圈"], "param_hints": ["topic"], }, { "intent": "policy_search", "patterns": ["政策", "公积金", "限购", "契税"], "param_hints": ["keyword"], }, ] def _write_log(self, message: str): entry = { "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "message": message, } self.logs.append(entry) print(f"[Harness] {entry['time']} - {message}") def _detect_intent(self, user_input: str): """基于规则检测用户意图,实际项目可以用大模型 + few-shot。""" for rule in self.intent_rules: for pat in rule["patterns"]: if pat in user_input: return rule["intent"] return "unknown" def _extract_params(self, user_input: str, tool_meta: dict): """从用户输入中抽取工具所需参数,这里用简单正则抽取。""" params = {} if "project_name" in tool_meta["required_params"]: # 简单规则:查找“某某项目/楼盘”,更精确的抽取需要 NER 或大模型 match = re.search(r"([\u4e00-\u9fa5A-Za-z0-9]{2,8}(?:项目|楼盘|府|苑|湾))", user_input) if match: params["project_name"] = match.group(1) else: # 兜底:默认给一个演示项目 params["project_name"] = "云栖上院" if "topic" in tool_meta["required_params"]: # 从“xx的文案”中提取主题 match = re.search(r"关于(.+?)的?(?:文案|推文|广告语|朋友圈)", user_input) if match: params["topic"] = match.group(1).strip() else: params["topic"] = "项目热销" if "keyword" in tool_meta["required_params"]: match = re.search(r"(?:查|问问|搜一下)?(.+?)(?:政策|公积金|限购|契税)", user_input) if match: params["keyword"] = match.group(1) else: params["keyword"] = "公积金" return params def _check_permission(self, tool_name: str) -> bool: """检查当前用户角色是否允许调用该工具。""" tool_meta = self.tools.get(tool_name) if not tool_meta: return False return self.user_role in tool_meta["roles"] def run(self, user_input: str, request_id: str = None): """执行一次完整的 Harness 流程。""" request_id = request_id or uuid.uuid4().hex[:8] self._write_log(f"[{request_id}] 收到用户输入:{user_input}") # 1. 意图识别 intent = self._detect_intent(user_input) self._write_log(f"[{request_id}] 意图识别结果:{intent}") if intent == "unknown": return { "ok": False, "message": "暂未理解你的意图,请尝试描述楼盘、客户或政策相关问题。", "request_id": request_id, } # 2. 工具选择 tool_meta = self.tools.get(intent) if not tool_meta: return { "ok": False, "message": "没有匹配到可用工具。", "request_id": request_id, } # 3. 权限校验 if not self._check_permission(intent): self._write_log(f"[{request_id}] 权限校验失败:当前角色 {self.user_role} 无权调用 {intent}") return { "ok": False, "message": f"当前角色无权限执行该操作,请联系管理员。", "request_id": request_id, } # 4. 参数填充 params = self._extract_params(user_input, tool_meta) missing = [p for p in tool_meta["required_params"] if p not in params] if missing: return { "ok": False, "message": f"缺少必要参数:{', '.join(missing)}", "request_id": request_id, } self._write_log(f"[{request_id}] 工具参数:{json.dumps(params, ensure_ascii=False)}") # 5. 执行工具 try: result = tool_meta["func"](**params) except Exception as e: self._write_log(f"[{request_id}] 工具执行异常:{str(e)}") return { "ok": False, "message": f"工具执行失败:{str(e)}", "request_id": request_id, } # 6. 结果封装 result["request_id"] = request_id return result4.4 数据文件准备
为了让代码可以直接运行,我们再准备两份演示数据。注意,在真实项目中,这些数据通常来自企业内部系统。
// 文件路径:ci-buddy-demo/data/projects.json [ { "name": "云栖上院", "location": "滨江区江虹路", "total_area": 126000, "plot_ratio": 2.2, "household_count": 780, "parking_count": 950, "status": "在售" }, { "name": "望江府", "location": "上城区近江路", "total_area": 88000, "plot_ratio": 3.1, "household_count": 420, "parking_count": 610, "status": "尾盘" } ]// 文件路径:ci-buddy-demo/data/customers.json [ { "name": "张女士", "project": "云栖上院", "last_follow_time": "2025-06-12", "intent_level": "A", "note": "重点关注 128 方户型,准备周末带家人复看。" }, { "name": "李先生", "project": "云栖上院", "last_follow_time": "2025-06-10", "intent_level": "B", "note": "对楼层和车位价格有顾虑。" }, { "name": "王先生", "project": "望江府", "last_follow_time": "2025-05-28", "intent_level": "C", "note": "暂时观望,等政策明确后再说。" } ]4.5 入口代码
最后是app.py,提供命令行交互方式,方便测试。
# 文件路径:ci-buddy-demo/app.py from harness import Harness def main(): print("CI Buddy 演示模式已启动。") print("当前登录角色:manager") print("可以尝试输入:查询云栖上院的楼盘信息 / 生成周报 / 帮我写一条关于低密社区的文案 / 查询公积金政策") print("输入 exit 退出。") harness = Harness(user_role="manager") while True: user_input = input("\nUser > ").strip() if not user_input: continue if user_input.lower() in ("exit", "quit"): break result = harness.run(user_input) print("\nBuddy > ") print(result) print("\nHarness 执行日志:") for log in harness.logs: print(f" {log['time']} - {log['message']}") harness.logs.clear() if __name__ == "__main__": main()4.6 运行与验证
先安装依赖。本示例没有额外第三方库依赖,只需要 Python 3.9 及以上版本。
cd ci-buddy-demo python app.py运行后输入:
查询云栖上院的楼盘信息理论上会看到类似输出:
Buddy > { "ok": true, "data": { "name": "云栖上院", "location": "滨江区江虹路", ... }, "message": "已找到项目:云栖上院", "request_id": "3f2a1c9e" }再输入:
生成周报你会看到 Harness 自动选择了get_customer_week_report工具,并返回了基于customers.json的汇总结果。
这个最小实现虽然简单,但已经具备了 Harness 的核心骨架:工具注册、意图识别、权限校验、参数填充、执行调度、日志追踪。把_detect_intent和_extract_params换成大模型调用,就是生产环境的基本形态。
5. 地产业务模块设计与进阶扩展
5.1 从演示到生产需要替换的部分
上面这个 demo 可以在本地跑通,但是距离真正的 CI Buddy 还有几步需要补齐:
- 真实数据接入:把本地 JSON 换成企业内部的 MySQL、Oracle、CRM 或者数据仓库。
- 大模型接入:把规则路由替换为 LLM 调用,建议使用工具调用(Function Calling)能力。
- 多轮对话管理:保存会话状态,让用户可以连续提问、追问。
- 审批流:当用户试图执行高权限操作(如调价、折扣、修改客户状态)时,自动进入审批流程。
- 前端接入:将 Harness 封装成 HTTP API,再对接企业微信、钉钉或 Web 工作台。
5.2 将 Harness 封装为 API 服务
为了让 CI Buddy 能接入 IM 或无代码平台,我们可以用 Flask 或 FastAPI 把 Harness 包成一个 HTTP 接口。
# 文件路径:ci-buddy-demo/api_server.py """ 将 Harness 封装为 HTTP API,使用 FastAPI 启动。 参考实现,需按实际环境安装 fastapi 和 uvicorn。 """ import uvicorn from fastapi import FastAPI from pydantic import BaseModel from harness import Harness app = FastAPI(title="CI Buddy API", version="0.1.0") # 不同用户角色初始化不同的 Harness 实例 harness_map = { "admin": Harness(user_role="admin"), "manager": Harness(user_role="manager"), "sales": Harness(user_role="sales"), "marketing": Harness(user_role="marketing"), "analysis": Harness(user_role="analysis"), } class ChatRequest(BaseModel): user_id: str role: str message: str @app.post("/chat") def chat(req: ChatRequest): harness = harness_map.get(req.role) if not harness: return {"ok": False, "message": "未知角色"} result = harness.run(req.message) return result if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000)启动服务后,可以用下面的命令测试:
curl -X POST http://localhost:8000/chat \ -H "Content-Type: application/json" \ -d '{"user_id": "u001", "role": "manager", "message": "查询公积金政策"}'这个接口可以被企业微信群机器人、钉钉自定义机器人或前端工作台直接调用。
5.3 把大模型路由接入 Harness
在生产环境中,规则匹配的意图识别不够灵活,需要接入大模型。下面给出一个基于 JSON 输出的路由思路,假设你的模型支持工具调用或结构化输出。
# 文件路径:ci-buddy-demo/llm_router_impl.py """ 大模型路由实现思路。 这里不绑定具体供应商,只演示如何把 LLM 返回的 JSON 映射到 Harness。 如果使用 OpenAI、DeepSeek、通义、百炼等平台的 Function Calling, 请按对应平台的调用方式调整。 """ import json def llm_detect_intent(user_input: str, tool_schemas: list) -> dict: """ 假设你已经调用大模型接口,并输入了工具 schema 列表。 模型返回形如: { "tool": "property_info", "params": {"project_name": "云栖上院"} } 这里省略真实 API 调用,只演示解析逻辑。 """ # 伪代码,实际项目中这里是: # resp = openai.ChatCompletion.create( # model="...", # messages=[...], # tools=tool_schemas, # tool_choice="auto", # ) # result = parse_response(resp) # 为了演示,直接返回一个写死的路由结果 result = { "tool": "property_info", "params": {"project_name": "云栖上院"}, } # 对模型输出做 JSON 校验,防止模型返回非合法 JSON try: parsed = result if isinstance(result, dict) else json.loads(result) return parsed except Exception as e: return {"tool": "unknown", "params": {}, "error": str(e)}这里想强调的是:真正生产项目要做的不是自己写 NER 或正则去抽取参数,而是让大模型根据工具 schema 返回结构化参数,Harness 再去执行。这样既能保证灵活性,又能通过 Harness 做参数和权限校验。
6. 常见问题与排查思路
在 CI Buddy 落地过程中,团队遇到的高频问题主要集中在下面几类。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 模型总能聊,但一调用工具就报错 | 工具 schema 描述不清晰,或模型不会填参数 | 精简工具数量,完善每个参数的示例值;在 Prompt 中补充工具调用示例 |
| 用户输入“帮我查一下客户”却被路由到“营销文案” | 意图规则太粗糙,或模型工具选择逻辑不收敛 | 增加负样本;在路由前加一层意图白名单;记录错误路由日志定期优化 |
| 调用工具后结果不稳定,有时读 A 数据有时读 B | 参数提取错误,项目名称匹配到了相似名称 | 引入项目名称规范表,使用向量匹配或模糊匹配;禁止模型自己造参数值 |
| 在产线被越权调用了敏感工具 | 权限只在前端做了控制,Harness 层没校验 | Harness 内部必须二次校验角色权限;工具调用日志留痕 |
| Token 消耗高,几百轮对话后变慢 | 上下文无限累积,工具描述过长 | 采用滑动窗口或摘要压缩;把动态工具和静态工具分离 |
| 大模型返回了幻觉数据,如虚构客户名 | 工具结果没有做数据校验,模型可能超出了已返回的数据范围 | 在 Harness 中限制最终生成文本只能引用工具返回字段;增加数据源标识和校验规则 |
如果遇到“意图识别不准”的问题,可以按以下顺序排查:
- 确认用户输入是否包含明确业务关键词。
- 查看 Harness 日志,确认当前路由命中了哪个意图。
- 检查工具描述中的示例是否和业务说法一致。
- 收集错误案例,补充到规则库或 Prompt 的 few-shot 示例中。
- 对同一句输入加一个“兜底回复”,不要让模型“硬选”一个工具。
7. 最佳实践与工程化建议
7.1 工具描述比 Prompt 更值得打磨
很多团队在做 Agent 时会把精力放在“如何让模型听懂人话”上,但实际上,工具描述的质量直接影响 Agent 能不能执行成功。建议每个工具描述都包含:
- 这个工具是什么;
- 什么时候应该调用它;
- 参数含义和取值范围;
- 至少一个输入输出示例。
比如“查询楼盘信息”的工具,描述可以写成:
工具名称:get_property_info 用途:查询楼盘基础信息。 何时使用:用户问某个项目的容积率、户型、位置、在售状态等信息时。 参数: project_name(必填):项目名称,必须使用系统中已有的标准名称,例如“云栖上院”。 示例: 输入:云栖上院的容积率是多少 调用:get_property_info(project_name="云栖上院")这样可以显著减少模型选错参数的概率。
7.2 权限设计必须分层
CI Buddy 涉及客户隐私、楼盘价格、销售提成等敏感数据。权限设计建议遵循最小权限原则:
- 置业顾问只能查询自己负责的客户和楼盘公开信息;
- 销售主管可以在 Harness 中查看团队汇总数据,但不能改价;
- 案场经理可以发起价格调整请求,但需要进入审批流;
- 所有高权限动作都要写入独立审计日志。
权限检查不应该只放在前端按钮上,Harness 层必须做第二次校验,否则调用 API 时可以绕过界面限制。
7.3 日志和追踪是 AI 应用的生命线
AI 应用比传统应用更依赖日志,因为模型行为存在不确定性。建议至少记录:
- 用户输入的原始内容;
- 路由结果(命中了哪个意图);
- 工具调用的参数和返回值;
- 权限校验结果;
- 最终返回给用户的内容;
- 耗时和 Token 消耗;
- 异常信息和堆栈。
有了这些日志,才能够在线上模型效果变差时快速定位是 Prompt 问题、工具问题还是数据问题。
7.4 灰度发布与人工兜底
不要一开始就把 CI Buddy 的结果直接推给所有用户。更稳妥的路线是:
- 内部小范围试用:让一个案场的一两个销售先试用,重点收集路由错误和工具报错。
- 人工审批模式:在周报、文案等场景,先让 AI 生成草稿,人工确认后再发布。
- 定期回看对话记录:每周挑 50 条真实对话,标记哪些回答不准确,再反哺优化 Prompt 和工具描述。
- 设置降级方案:当大模型服务不可用或超时时,返回“人工客服/资料查询”兜底入口,避免业务中断。
7.5 提示词与配置分离
对于非开发人员,比如运营或销售管理人员,他们不会想理解什么是 Function Calling,也不该改动代码。更好的做法是:把工具描述、提示词示例、路由规则放到配置中心或后台管理页里,由项目负责人按业务变化调整。
一个简化的配置示例:
# 文件路径:ci-buddy-demo/config/tools.yaml tools: property_info: name: get_property_info description: 查询楼盘基础信息 required_params: - project_name roles: - sales - manager - admin risk: low customer_week_report: name: get_customer_week_report description: 生成本周客户跟进摘要 required_params: [] roles: - manager - admin risk: medium这样后续调整权限或新增工具时,不需要重新发版。
8. 给地产团队的落地行动清单
如果你正在推动类似 CI Buddy 的项目,这里有一份可以直接拿来用的行动清单:
- 选一个场景:不要做“万能助手”,先选择“楼盘信息问答”或“客户周报生成”这类数据边界清晰、结果容易验证的场景。
- 整理标准数据字典:把项目名、客户状态、意向等级、户型名称等字段统一成标准叫法,这是模型正确调用工具的前提。
- 先搭 Harness,再调 Prompt:先把工具注册、权限校验、日志框架搭好,再让大模型介入意图理解。
- 用真实对话做评估:收集 100 条业务真实问题,作为回归测试集,每次优化 Prompt 或添加工具后都跑一遍,防止“修好一个错、弄坏一片”。
- 上线前加人工确认:涉及对外发布的文案、客户跟进记录、政策解读等场景,先采用人审模式。
Harness 的火爆不是概念炒作,而是 AI 应用从“聊天问答”走向“业务执行”的必然结果。对地产行业来说,CI Buddy 这类专属助手能不能真正落地,关键不在于模型选得多强,而在于执行框架是否清晰、数据是否规范、权限是否可控。
建议你在本地把上面的最小示例跑一遍,理清工具注册、意图路由、权限校验这条链路,再结合具体的业务流程迭代。欢迎在评论区聊聊你所在团队准备先从哪个场景入手,或者在实际落地中踩到了哪些坑。