ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
阶段 4:对话式量刑建议 Agent。
|
||||
|
||||
把「案件原型 + 层次因子重要性」当决策逻辑来用:
|
||||
1. 从用户口语描述里抽取已知因子(复用抽取器,含罪名判定);
|
||||
2. 按**全局因子重要性顺序**,找出仍缺失、但很重要的因子,生成引导性追问;
|
||||
3. 信息补全后,把案件**匹配到最近的案件原型**;
|
||||
4. 用 LLM 把该原型的统计数据(典型刑期区间、定义性关键因子)组织成一段
|
||||
有判例支持、可解释的中文建议(附法律免责声明)。
|
||||
|
||||
所有刑期数字都来自原型统计,LLM 只负责"把数字讲清楚",不自行编造。
|
||||
"""
|
||||
from config import MODEL, get_client
|
||||
from archetypes import nearest_archetype
|
||||
from discovery import all_factors
|
||||
|
||||
DISCLAIMER = (
|
||||
"【免责声明】本回答由教学实验中的统计模型自动生成,仅用于演示"
|
||||
"『从结构化数据中提取隐性知识』这一技术,不构成任何法律意见。真实案件量刑受"
|
||||
"法律条文、司法解释、地域与具体情节等大量因素影响,请务必咨询专业律师。"
|
||||
)
|
||||
|
||||
|
||||
class LegalAdvisorAgent:
|
||||
def __init__(self, schema, model):
|
||||
self.schema = schema
|
||||
self.model = model # archetypes.fit() 产出的模型
|
||||
self.client = get_client()
|
||||
self._factor = {f["key"]: f for f in all_factors(schema)}
|
||||
|
||||
# --- 步骤 1:抽取已知因子 ---
|
||||
def extract_known(self, case_text):
|
||||
from extractor import extract_one
|
||||
return extract_one(case_text, schema=self.schema, client=self.client)
|
||||
|
||||
# --- 步骤 2:按全局重要性顺序,追问缺失的重要因子 ---
|
||||
def missing_important_questions(self, known):
|
||||
questions, asked = [], set()
|
||||
for item in self.model["global_importance"]:
|
||||
col = item["feature"]
|
||||
# 从列名解析出因子 key(跳过罪名维——已判定)
|
||||
if col.startswith("charge="):
|
||||
continue
|
||||
key = col.split(":", 1)[1].split("=", 1)[0]
|
||||
if key in asked or key not in known:
|
||||
continue
|
||||
if known.get(key) is None: # 该因子适用于本罪名但用户尚未提供
|
||||
f = self._factor.get(key, {})
|
||||
questions.append({
|
||||
"factor": key,
|
||||
"name_cn": f.get("name_cn", key),
|
||||
"importance": item["score"],
|
||||
"question": f.get("question") or f"请补充:{f.get('name_cn', key)}?",
|
||||
})
|
||||
asked.add(key)
|
||||
return questions
|
||||
|
||||
# --- 步骤 3+4:匹配最近原型并给出建议 ---
|
||||
def advise(self, known):
|
||||
matched = nearest_archetype(self.model, known)
|
||||
# fit() can return n_archetypes=0 when every charge has too few samples to cluster.
|
||||
if matched is None:
|
||||
raise ValueError("模型中没有可用案件原型,无法给出量刑建议(样本过少无法聚类)")
|
||||
arch, dist = matched
|
||||
m = arch["months"]
|
||||
defining = ";".join(
|
||||
f"{d['label']}({d['direction']},典型 {d['typical']})"
|
||||
for d in arch["defining"][:4]
|
||||
)
|
||||
evidence = (
|
||||
f"- 命中案件原型 #{arch['id']}({arch['charge']},该原型含 {arch['size']} 例),"
|
||||
f"匹配距离 {dist:.2f}\n"
|
||||
f"- 该原型典型刑期:中位 {m['median']:.0f} 个月,区间 {m['min']:.0f}~{m['max']:.0f} 个月\n"
|
||||
f"- 定义该原型的关键因子:{defining}"
|
||||
)
|
||||
known_desc = self._describe_known(known)
|
||||
|
||||
system = (
|
||||
"你是一名严谨的司法数据分析助手。下面给出一个数据驱动模型把某案件匹配到的"
|
||||
"『案件原型』及其统计数据(数字均来自模型,不得改动)。请用中文写一段 160 字"
|
||||
"以内、条理清晰的量刑参考:先说明命中的原型及其典型刑期区间,再点明本案与该"
|
||||
"原型共有的关键因子如何影响结果。不要编造模型未给出的数字,不要给确定性承诺,"
|
||||
"不要重复免责声明(系统会另附)。"
|
||||
)
|
||||
user = f"本案已知因子:\n{known_desc}\n\n模型匹配依据:\n{evidence}"
|
||||
resp = self.client.chat.completions.create(
|
||||
model=MODEL, temperature=0.3,
|
||||
messages=[{"role": "system", "content": system},
|
||||
{"role": "user", "content": user}],
|
||||
)
|
||||
return arch, resp.choices[0].message.content.strip() + "\n\n" + DISCLAIMER
|
||||
|
||||
def _describe_known(self, known):
|
||||
parts = [f"罪名:{known.get('charge')}"]
|
||||
for key, v in known.items():
|
||||
if key == "charge":
|
||||
continue
|
||||
f = self._factor.get(key, {})
|
||||
if v is None:
|
||||
tag = "未知"
|
||||
elif isinstance(v, bool):
|
||||
tag = "是" if v else "否"
|
||||
else:
|
||||
tag = str(v)
|
||||
parts.append(f"{f.get('name_cn', key)}:{tag}")
|
||||
return "\n".join(" " + p for p in parts)
|
||||
Reference in New Issue
Block a user