prompts.py 14.2 KB
Newer Older
陈正乐 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428

from typing import Any
from langchain.prompts import StringPromptTemplate,PromptTemplate
from pydantic import BaseModel, validator
from langchain.chains.router.llm_router import RouterOutputParser


# template="""
# {knowledge}
# 请从上述内容中提取 {elements} 这些元素的信息,每个元素以 "名称:值" 的形式输出,空行分隔
# """

template="""
{knowledge}

请从上述提供的合同文本中提取出指定元素相关的信息,并以“名称:值”的格式输出识别结果,用空行分隔,不要使用 markdown 格式。例如:
测试元素1:test
测试元素2:test2

你需要提取的元素有:
{elements}
"""

prompt=PromptTemplate.from_template(template)


class ElementsPromptTemplate(StringPromptTemplate, BaseModel):
        
    def format(self, **kwargs) -> str:
        if "elements" not in kwargs or kwargs["elements"] is None:
            elements = []
        else:
            elements=kwargs["elements"]
            # elements = "\n".join([f"{i+1}. {e}" for i, e in enumerate(elements)])
            elements = "\n".join(elements)
            print(elements)
        if "knowledge" not in kwargs:
            raise ValueError("knowledge is required")
        knowledge = kwargs["knowledge"]

        return prompt.format(knowledge=knowledge, elements=elements)

    def _prompt_type(self):
        return "contract-elements"





template_foreach="""
{knowledge}

请从上述提供的合同文本中提取出 {element} 的信息,并以“{element}:”的形式进行输出。
"""

prompt_foreach=PromptTemplate.from_template(template_foreach)

class ElementPromptTemplate(StringPromptTemplate, BaseModel):
        
    def format(self, **kwargs) -> str:
        if "element" not in kwargs or kwargs["element"] is None:
            element =  ""
        else:
            element=kwargs["element"]
        if "knowledge" not in kwargs:
            raise ValueError("knowledge is required")
        knowledge = kwargs["knowledge"]

        return prompt_foreach.format(knowledge=knowledge, element=element)

    def _prompt_type(self):
        return "contract-element"

#========================
#   documentqa chain prompt
#   documentqa chain prompt
#   documentqa chain prompt
#========================

#========================
#   GLM  refine
#========================
#------------------------
#   总结
#------------------------
summarise_prompt = "对以下内容进行简要总结:\n----------\n{text}\n----------\n,总结:"
refine_summarise_prompt = "你的工作是生成总结。\n我们已经提供了一段摘要:{existing_answer}\n我们需要从下面的上下文中补充和完善摘要,如果上下文没有用处,请返回原始摘要:\n----------\n{text}\n----------\n"
SUMMARISE_PROMPT = PromptTemplate(
        input_variables=["text"],
        template=summarise_prompt,
        #template="Define {concept} with a real-world example?",
    )
REFINE_SUMMARISE_PROMPT = PromptTemplate(
        input_variables=["existing_answer", "text"],
        template=refine_summarise_prompt,
        #template="Define {concept} with a real-world example?",
    )

#------------------------
#   提问
#------------------------
qa_prompt = """请根据下面的材料回答问题:"{question}",只根据材料内容进行回答,如果问题与提供的材料无关,请回答"对不起,我不知道",另外也不要回答无关答案:
-------------------
{context}
-------------------"""
QA_PROMPT = PromptTemplate(template=qa_prompt, input_variables=["context", "question"])

refine_qa_prompt = """你的工作是根据新的Context补充Exist_answer。
Exist_answer:
-------------------
{existing_answer}
-------------------
Context:
-------------------
{context}
-------------------
Question: 
-------------------
{question}
-------------------
如果上下文没有用处,请返回原始答案,如果query与提供的材料无关,请回答"对不起,我不知道",另外也不要回答无关答案"""

REFINE_QA_PROMPT = PromptTemplate(
        input_variables=["existing_answer", "context","question"],
        template=refine_qa_prompt,
        #template="Define {concept} with a real-world example?",
    )

#------------------------
#   提取
#------------------------

extraction_prompt="""你的工作是合同要素提取,根据提供的资料提取合同要素,不要造假答案。如果资料没用,回复“无”。需要提取的要素列表(用“、”分割):{question}。
示例:----------
要素列表:签订日期、甲方
回答格式如下:
签订日期:2020年1月1日
甲方:无
----------

下面一直到结束是提供的资料:
{context}"""

EXTRACTION_PROMPT = PromptTemplate(template=extraction_prompt, input_variables=["context", "question"])
#你的工作是在现有的Exist_answer基础上,根据新的Context提取"keys"中key的值,并以"key:value"形式给出答案,用空行分隔。

refine_extraction_prompt="""你的工作是合同要素提取,根据提供的资料完善现有的要素信息。如果资料没用,请返回现有的要素信息,不要造假答案。需要提取的要素列表(用“、”分割):{question}。
示例:----------
要素列表:签订日期、甲方
回答格式如下:
签订日期:2020年1月1日
甲方:无
----------

现有的要素信息如下:
{existing_answer}
---------------------
下面一直到结束是提供的资料:
{context}"""


REFINE_EXTRACTION_PROMPT = PromptTemplate(
        input_variables=["existing_answer", "context","question"],
        template=refine_extraction_prompt,
        #template="Define {concept} with a real-world example?",
    )

foreach_extraction_prompt="""你的工作是从资料中提取要素:{question}。如果资料无法提取要素信息,回复“无”。

下面是提供的资料:
{context}

---------------------
请注意输出格式以“{question}:”开头,紧接着给出答案。"""

FOREACH_EXTRACTION_PROMPT = PromptTemplate(template=foreach_extraction_prompt, input_variables=["context", "question"])
#你的工作是在现有的Exist_answer基础上,根据新的Context提取"keys"中key的值,并以"key:value"形式给出答案,用空行分隔。

foreach_refine_extraction_prompt="""你的工作是从资料中提取要素:{question}。如果资料中要素信息明确,完善现有的答案并返回。如果资料无法提取要素信息,请返回现有的答案。另外也不要回答无关答案。

现有的答案:
{existing_answer}

---------------------

下面是提供的资料:
{context}

---------------------
请注意输出格式以“{question}:”开头,直接给出答案。"""


FOREACH_REFINE_EXTRACTION_PROMPT = PromptTemplate(
        input_variables=["existing_answer", "context","question"],
        template=foreach_refine_extraction_prompt,
        #template="Define {concept} with a real-world example?",
    )



#========================
#   map reduce prompt
#   map reduce prompt
#   map reduce prompt
#========================

glm_chat_question_prompt = """你的工作是找出Context中与Question相关的文本,返回原始文本。如果Question与提供的Context无关,请回答"相关文本:无",另外也不要回答无关答案:
注意:回复以“相关文本:”开头,不要包含Question本身
Question:
-----------
{question}
-----------
Context:
-----------
{context}
-----------"""

GLM_CHAT_QUESTION_PROMPT = PromptTemplate(
    template=glm_chat_question_prompt,
    input_variables=["question","context"],
)

glm_chat_combine_prompt = """你的工作是根据资料回答问题。问题:{question},下面是提供的资料。如果资料与问题无关,回复“不知道”,不要添加任何不相关的内容。
注意:每个文本以“相关文本:”开头
<< 资料 >>
{summaries}
"""

GLM_CHAT_COMBINE_PROMPT = PromptTemplate(
    template=glm_chat_combine_prompt,
    input_variables=["question","summaries"],
)

glm_map_extraction_prompt="""你的工作是合同要素提取,根据提供的资料提取合同要素,不要造假答案。如果资料没用,回复“无”。需要提取的要素列表(用“、”分割):{question}。
示例:----------
要素列表:签订日期、甲方
回答格式如下:
签订日期:2020年1月1日
甲方:无
----------

下面一直到结束是提供的资料:
{context}"""

GLM_MAP_EXTRACTION_PROMPT = PromptTemplate(
    template=glm_map_extraction_prompt,
    input_variables=["question","context"],
)

glm_map_extraction_combine_prompt="""你的工作是将资料里面的要素信息根据需要提取的要素信息汇总。需要提取的要素列表(用“、”分割):{question}。
示例:----------
要素列表:签订日期、甲方
回答格式如下:
签订日期:2020年1月1日
甲方:无
----------

下面一直到结束是提供的资料:
{summaries}"""

GLM_MAP_EXTRACTION_COMBINE_PROMPT = PromptTemplate(
    template=glm_map_extraction_combine_prompt,
    input_variables=["question","summaries"],
)

#===================================
#   foreach prompt
#===================================
foreach_map_q_extraction_prompt = """你的工作是找出资料中与“{question}”相关的文本,返回原始文本。如果找不到相关文档,请回答"相关文本:无"。不要生成与资料不相关的文字:

下面是提供的资料:
{context}

---------------------
请注意输出格式以“相关文本:”开头。"""

FOREACH_MAP_Q_EXTRACTION_PROMPT = PromptTemplate(
    template=foreach_map_q_extraction_prompt,
    input_variables=["question","context"],
)

foreach_map_extraction_prompt="""你的工作是从资料中提取要素:{question}。如果资料无法提取要素信息,回复“无”。

下面是提供的资料:
{summaries}

---------------------
请注意输出格式以“{question}:”开头,紧接着给出答案。"""


FOREACH_MAP_EXTRACTION_PROMPT = PromptTemplate(
        input_variables=["summaries","question"],
        template=foreach_map_extraction_prompt,
        #template="Define {concept} with a real-world example?",
    )

#========================
#   百度 ernie
#========================
ernie_chat_question_prompt = """现在需要你在'''中的资料中找出与问题相关的段落,回答用“相关资料:”开头。
问题是:{question}。
'''
{context}
'''
注意:如果没有找到与问题相关的段落就回答“无”。"""
ernie_chat_combine_prompt = """现在需要你根据'''中的资料回答问题,如果资料与问题无关就回复“不知道”,不要回答任何不相关的内容。
问题是:{question}。
'''
{summaries}
'''"""
ERNIE_GLM_CHAT_QUESTION_PROMPT = PromptTemplate(
    template=ernie_chat_question_prompt,
    input_variables=["question","context"],
)
ERNIE_GLM_CHAT_COMBINE_PROMPT = PromptTemplate(
    template=ernie_chat_combine_prompt,
    input_variables=["question","summaries"],
)

map_reducce_prompt = """请对下面内容做一个简要总结:

"{text}"

"""
MAP_REDUCE_SUMMARISE_PROMPT = PromptTemplate(template=map_reducce_prompt, input_variables=["text"])

ernie_extraction_prompt="""请从'''包裹的资料中按要求抽取出重要信息,需要你提取的信息列表:{question}。若无法提取相关信息,用"未知"表示。
资料如下:
'''
{context}
'''

输出要求:
以json格式输出,输出json中key必须含有\"{question}\"几项。除json以外不要添加任何内容。
```json
{{
    "XXX":"XXXXXX",
    "XXX":"未知"
}}
```
"""

ERNIE_EXTRACTION_PROMPT = PromptTemplate(template=ernie_extraction_prompt, input_variables=["context", "question"])
#你的工作是在现有的Exist_answer基础上,根据新的Context提取"keys"中key的值,并以"key:value"形式给出答案,用空行分隔。

ernie_refine_extraction_prompt="""由于原始文本太长,关键信息需要分段提取。\"\"\"包裹的是历史提取的信息,请根据'''包裹的新资料补充历史提取的信息中\"未知\"的部分,历史提取的信息中已知部分请保留输出。
历史提取的信息:
\"\"\"{existing_answer}\"\"\"

资料如下:
'''
{context}
'''

输出要求:
如果新资料没有帮助,请返回\"\"\"包裹的历史提取的信息。
以json格式输出,输出json中key必须含有\"{question}\"几项。除json以外不要添加任何内容。
```json
{{
    "XXX":"XXXXXX",
    "XXX":"未知"
}}
```
"""


ERNIE_REFINE_EXTRACTION_PROMPT = PromptTemplate(
        input_variables=["existing_answer", "context","question"],
        template=ernie_refine_extraction_prompt,
    )


#========================
#   route chain prompt
#   route chain prompt
#   route chain prompt
#========================
MULTI_PROMPT_ROUTER_TEMPLATE2 = """\
Given a raw text input to a language model select the model prompt best suited for \
the input. You will be given the names of the available prompts and a description of \
what the prompt is best suited for. You may also revise the original input if you \
think that revising it will ultimately lead to a better response from the language \
model.

<< FORMATTING >>
Return a markdown code snippet with a JSON object formatted to look like:
{{{{
    "destination": string \\ name of the prompt to use or "default"
    "next_inputs": string \\ a potentially modified version of the original input
}}}}

REMEMBER: "destination" MUST be one of the candidate prompt names specified below OR \
it can be "default" if the input is not well suited for any of the candidate prompts.
REMEMBER: "next_inputs" can just be the original input if you don't think any \
modifications are needed.

<< CANDIDATE PROMPTS >>
{destinations}

<< INPUT >>
{{input}}

<< OUTPUT (OUTPUT must be json string and don't include Note) >>
"""

prompt_infos = [
{
    "name": "summer",
    "description": "文档总结和摘要很专业",
},
{
    "name": "expertor",
    "description": "基于输入的文档,回答文档中相关的问题很专业",
},
{
    "name": "extractor",
    "description": "从文档中提取关键信息和事实很专业",
}
]
destinations = [f"{p['name']}: {p['description']}" for p in prompt_infos]
destinations_str = "\n".join(destinations)
router_template = MULTI_PROMPT_ROUTER_TEMPLATE2.format(destinations=destinations_str)
ROUTER_PROMPT = PromptTemplate(
    template=router_template,
    input_variables=["input"],
    output_parser=RouterOutputParser(),
)