import json
from typing import Literal, Optional, Union, List
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import PromptTemplate
from pydantic import BaseModel
from common.llm import my_llm
# ======================
# 枚举定义
# ======================
EntityType = Literal["Symptom", "Disease", "Formula", "Herb", "Effect", "Source"]
RelationType = Literal[
"TREATS_DISEASE",
"ALLEVIATES_SYMPTOM",
"HAS_EFFECT",
"HAS_INGREDIENT",
"HAS_SYMPTOM",
"FROM_SOURCE"
]
# ======================
# 属性定义
# ======================
class FormulaAttributes(BaseModel):
alias: Optional[str] = None
effect: Optional[str] = None
indication: Optional[str] = None
taboo: Optional[str] = None
usage: Optional[str] = None
class HerbAttributes(BaseModel):
dosage: Optional[str] = None
effect: Optional[str] = None
indication: Optional[str] = None
meridian: Optional[str] = None
origin: Optional[str] = None
place: Optional[str] = None
processing: Optional[str] = None
property_flavor: Optional[str] = None
taboo: Optional[str] = None
traits: Optional[str] = None
# ======================
# 实体与关系结构
# ======================
class Entity(BaseModel):
name: str
type: EntityType
attributes: Optional[Union[FormulaAttributes, HerbAttributes]] = None
class Relation(BaseModel):
subject: str
subject_type: EntityType
relation: RelationType
object: str
object_type: EntityType
#Pydantic限定了是他的输出格式
class TCMKnowledgeGraph(BaseModel):
entities: List[Entity]
relations: List[Relation]
# 初始化解析器
parser = JsonOutputParser(pydantic_object=TCMKnowledgeGraph)
# 定义 Prompt
prompt = PromptTemplate(
template=(
"你是一个中医知识图谱抽取专家。请从以下文本中提取结构化知识:\n"
"仅当文本中存在实体之间的明确关系时(如‘某方剂治疗某疾病’、‘某药材具有某功效’、‘方剂包含药材’等),才进行抽取。\n"
"如果文本中仅描述单个实体的信息、未涉及其他实体或关系,请不要抽取,返回空结构:\n"
"{{\"entities\": [], \"relations\": []}}\n\n"
"【实体类型说明】\n"
"- Symptom:症状,如咳嗽、腹痛等\n"
"- Disease:疾病,如感冒、肺炎、肾虚等\n"
"- Formula:方剂,如四君子汤、桂枝汤等\n"
"- Herb:药材,如人参、黄芪、丁香等\n"
"- Effect:功效,如补气、活血、祛湿、止痛等\n"
"- Source:出处,如《本草纲目》《伤寒论》等\n\n"
"【关系类型说明】\n"
"- TREATS_DISEASE:方剂或药材治疗某种疾病\n"
"- ALLEVIATES_SYMPTOM:方剂或药材缓解某种症状\n"
"- HAS_EFFECT:方剂或药材具有某种功效\n"
"- HAS_INGREDIENT:方剂包含某种药材\n"
"- HAS_SYMPTOM:疾病包含某种症状\n"
"- FROM_SOURCE:方剂出自某文献或出处\n\n"
"若文本涉及方剂或药材,请补充对应的属性字段(如功效、性味、剂量等)。\n"
"如果文本主要是讲方剂的,请不要抽取药材的属性字段。\n"
"如果文本主要是讲药材的,请不要抽取方剂的属性字段。\n"
"如果值为空null,则不必显示键的值。"
"所有输出必须严格符合以下 JSON 格式:\n"
"{format_instructions}\n\n"
"输入文本:{text}"
),
input_variables=["text"],
partial_variables={"format_instructions": parser.get_format_instructions()}
)
# ======================
# 主函数封装
# ======================
def extract_tcm_knowledge(text: str):
# 构建抽取链
chain = prompt | my_llm | parser
return chain.invoke({"text": text})
# ======================
# Alpaca 微调数据集
# ======================
# instruction 固定不变,input 是中药详情原文,output 是抽取结果的 json 串。
# 常量和构造函数放在这里而不是放在 01_/02_ 脚本里:数字开头的模块名不是合法
# 标识符,两个脚本没法互相 import,共享的东西只能落在这个正常命名的模块。
ALPACA_INSTRUCTION = "请从以下中医文本中抽取知识图谱结构,包括实体与关系。"
def build_alpaca_record(text, entities, relations):
"""把一条抽取结果组装成 Alpaca 格式的样本。
output 按 Alpaca 约定是字符串,不是嵌套对象,所以这里 dumps 成 json 串。
ensure_ascii=False 让中文在数据集里保持可读;键顺序固定成
entities 在前、relations 在后,重跑时同样的抽取结果能得到同样的字节。
"""
return {
"instruction": ALPACA_INSTRUCTION,
"input": text,
"output": json.dumps(
{"entities": entities, "relations": relations},
ensure_ascii=False,
),
}
if __name__ == '__main__':
text="""
中药名:一匹绸
分类:化痰止咳平喘药
链接:https://zhongyibaike.com/wiki/一匹绸
## 名称
白面水鸡(《陆川本草》),白背丝绸(《生草药手册》),白底丝绸(《岭南草药志》),绸缎藤、银背藤(《广西药植名录》),一匹绸(《广西中草药》)。
## 一匹绸的种植和炮制
### 来源
为旋花科植物白鹤藤的茎叶。秋季采收。
【原形态】
缠绕藤本。叶卵形至椭圆形,长5~11厘米,宽3~9厘米,先端短尖或钝,基部浑圆或有时微心形,上面秃净或近秃净,下面密被银色紧贴的柔毛。花序腋生或顶生,头状或伞状;花序柄长3.5~7厘米,密被银色柔毛;花柄短,长约5毫米或不及;苞片大,萼片5,矩圆状卵形或卵形,外面的长9~10毫米,内面的较小,外密被银色柔毛;花冠漏斗状,白色,长2.7~2.8厘米,外被银色偃毛,裂片矩圆形,长1.5厘米内外;雄蕊5;子房4室,花柱线形。果近球形,径约8厘米,胭脂色,为卵形凹陷的宿萼所包围。花期秋季。
【生境分布】
生态环境:生于疏林下或路边灌丛中、河边。
资源分布:分布于广东、海南、广西等地。
### 性味
①《陆川本草》:苦辛,凉。
②《岭南草药志》:味微酸微苦,性凉。
### 性状
干燥茎叶,茎扭曲,表面暗灰棕色,有纵沟纹,断面绿白色,有明显的维管束,淡棕色。叶稍卷曲,质脆易碎,表面暗棕色至紫色,背面浅灰绿色,紧贴丝光毛。触之柔软。产广东、广西等地。
## 一匹绸的效果
### 功效
为旋花科植物白鹤藤的茎叶。用于热咳,痰喘,吐血,崩漏,白带,跌打损伤,风湿痛,疮毒。
### 主治
化痰止咳,理血祛风。治热咳,痰喘,吐血,崩漏,白带,跌打损伤,风湿痛,疮毒。
①《本草求原》:叶敷烂脚,化腐疮。
②《岭南采药录》:蛊胀,和米与黄糖捣烂煎香食之;肿胀,和苍术煎汤熏蒸之。
③《陆川本草》:叶:治肺热咳嗽痰喘。
④《广西药植名录》:消痰,润肺,止咳,止血。治肺痨,乳痈,水火烫伤。
⑤《广西中草药》:理血,祛风,除湿。治跌打损伤,内外伤出血及妇女血崩,白带。
⑥《文山中草药》:舒筋活络,祛风除湿,止咳化痰,调经止血。治跌打损伤,风湿疼痛,急慢性支气管炎。
### 用法用量
内服:煎汤,9~15克。
外用:煎水熏洗或捣敷。
## 一匹绸的药方
①治急、慢性支气管炎:白鹤藤(干品)五钱至一两,水煎服。(广州部队《常用中草药手册》)
②治内伤吐血:一匹绸叶、 虎杖 、 旱莲草 、 龙芽草 各一两,水煎服。(《广西中草药》)
③治崩漏:㈠一匹绸叶、 走马胎叶 、 龙芽草 各一两,捣烂,水煎服。(《广西中草药》)㈡紫苞银背藤叶三至四片,研末,酒送服。(《云南中草药》)
④治跌打积瘀,经络不和:一匹绸一两,水煎冲酒服。(《广西中草药》)
⑤治白带:一匹绸一两,小榕树须五钱, 鸡冠花 一两,水煎服。(《广西中草药》)
⑥治疮毒、烂脚:白鹤藤、 蒲公英 、 银花藤 煎水洗之,有消炎、化腐、去毒之效。(《岭南草药志》)
"""
result=extract_tcm_knowledge(text)
print(result)