-
-
Notifications
You must be signed in to change notification settings - Fork 174
/
doc-chat-2.py
137 lines (123 loc) · 5.07 KB
/
doc-chat-2.py
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
"""
2-agent doc-chat:
WriterAgent is in charge of answering user's question.
Breaks it down into smaller questions (if needed) to send to DocAgent,
who has access to the docs via a vector-db.
python3 examples/docqa/doc-chat-2.py
"""
from rich import print
from rich.prompt import Prompt
import os
from langroid.agent.special.doc_chat_agent import (
DocChatAgent,
DocChatAgentConfig,
)
import langroid.language_models as lm
from langroid.mytypes import Entity
from langroid.parsing.parser import ParsingConfig, PdfParsingConfig, Splitter
from langroid.agent.chat_agent import ChatAgent, ChatAgentConfig
from langroid.agent.task import Task
from langroid.agent.tools.recipient_tool import RecipientTool
from langroid.utils.configuration import set_global, Settings
from langroid.utils.constants import NO_ANSWER
from fire import Fire
os.environ["TOKENIZERS_PARALLELISM"] = "false"
def main(
debug: bool = False,
nocache: bool = False,
model: str = lm.OpenAIChatModel.GPT4o,
) -> None:
llm_config = lm.OpenAIGPTConfig(chat_model=model)
config = DocChatAgentConfig(
llm=llm_config,
n_query_rephrases=0,
hypothetical_answer=False,
assistant_mode=True,
n_neighbor_chunks=2,
parsing=ParsingConfig( # modify as needed
splitter=Splitter.TOKENS,
chunk_size=100, # aim for this many tokens per chunk
n_neighbor_ids=5,
overlap=20, # overlap between chunks
max_chunks=10_000,
# aim to have at least this many chars per chunk when
# truncating due to punctuation
min_chunk_chars=200,
discard_chunk_chars=5, # discard chunks with fewer than this many chars
n_similar_docs=5,
# NOTE: PDF parsing is extremely challenging, each library has its own
# strengths and weaknesses. Try one that works for your use case.
pdf=PdfParsingConfig(
# alternatives: "unstructured", "pdfplumber", "fitz"
library="pdfplumber",
),
),
)
set_global(
Settings(
debug=debug,
cache=not nocache,
)
)
doc_agent = DocChatAgent(config)
print("[blue]Welcome to the document chatbot!")
doc_agent.user_docs_ingest_dialog()
print("[cyan]Enter x or q to quit, or ? for evidence")
doc_task = Task(
doc_agent,
interactive=False,
name="DocAgent",
done_if_no_response=[Entity.LLM], # done if null response from LLM
done_if_response=[Entity.LLM], # done if non-null response from LLM
)
writer_agent = ChatAgent(
ChatAgentConfig(
name="WriterAgent",
llm=llm_config,
vecdb=None,
)
)
writer_agent.enable_message(RecipientTool)
writer_task = Task(
writer_agent,
name="WriterAgent",
interactive=False,
system_message=f"""
You are tenacious, creative and resourceful when given a question to
find an answer for. You will receive questions from a user, which you will
try to answer ONLY based on content from certain documents (not from your
general knowledge). However you do NOT have access to the documents.
You will be assisted by DocAgent, who DOES have access to the documents.
Here are the rules:
(a) when the question is complex or has multiple parts, break it into small
parts and/or steps and send them to DocAgent
(b) if DocAgent says {NO_ANSWER} or gives no answer, try asking in other ways.
(c) Once you collect all parts of the answer, say "DONE"
and show me the consolidated final answer.
(d) DocAgent has no memory of previous dialog, so you must ensure your
questions are stand-alone questions that don't refer to entities mentioned
earlier in the dialog.
(e) if DocAgent is unable to answer after your best efforts, you can say
{NO_ANSWER} and move on to the next question.
(f) answers should be based ONLY on the documents, NOT on your prior knowledge.
(g) be direct and concise, do not waste words being polite.
(h) if you need more info from the user, before asking DocAgent, you should
address questions to the "User" (not to DocAgent) to get further
clarifications or information.
(i) Always ask questions ONE BY ONE (to either User or DocAgent), NEVER
send Multiple questions in one message.
(j) Use bullet-point format when presenting multiple pieces of info.
(k) When DocAgent responds without citing a SOURCE and EXTRACT(S), you should
send your question again to DocChat, reminding it to cite the source and
extract(s).
Start by asking the user what they want to know.
""",
)
writer_task.add_sub_task(doc_task)
while True:
query = Prompt.ask("[blue]How can I help?")
if query in ["x", "q"]:
break
writer_task.run(query)
if __name__ == "__main__":
Fire(main)