Я пытаюсь сесть на поезд LCEL и Langserve, но у меня возникли небольшие проблемы с пониманием некоторой «магии», связанной с доступом к переменным, установленным в словаре конвейера.
Переменные кажутся разрешимыми из шаблонов подсказок. Я хотел бы получить эти значения в пользовательских функциях и т. д., но мне не ясно, как получить к ним прямой доступ. Возьмем следующий надуманный пример, целью которого является возврат исходного документа, а также ответа в ответе:
class ChatResponse(BaseModel):
answer: str
sources: List[Document]
store = FAISS.from_texts(
["harrison worked at kensho"], embedding=OpenAIEmbeddings()
)
retriever = store.as_retriever()
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
llm = ChatOpenAI()
def format_response(answer):
sources = [] # TODO lookup source documents (key: 'context')
return ChatResponse(answer=answer, sources=sources)
retrieval_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
| RunnableLambda(format_response)
)
app = FastAPI()
add_routes(app, retrieval_chain, path = "/chat", input_type=str, output_type=ChatResponse)
В format_response
я оставил TODO
для поиска исходных документов. Я хотел бы получить исходные документы из ключа context
конвейера. Как мне получить доступ к этому ключу, который был установлен на первом этапе цепочки?
из документации по адресу https://python.langchain.com/docs/use_cases/question_answering/sources/
from langchain_core.runnables import RunnableParallel
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain_from_docs = (
RunnablePassthrough.assign(context=(lambda x: format_docs(x["context"])))
| prompt
| llm
| StrOutputParser()
)
rag_chain_with_source = RunnableParallel(
{"context": retriever, "question": RunnablePassthrough()}
).assign(answer=rag_chain_from_docs)
тогда это:
rag_chain_with_source.invoke("where did harrison work ?")
возвращает:
{'context': [Document(page_content='harrison worked at kensho')],
'question': 'where did harrison work ?',
'answer': 'Harrison worked at Kensho.'}
Думаю, я увлекся размышлениями об этом немного в стороне. Глядя на пример цитат, я вижу, как, создав несколько цепочек и используя RunnableParallel для их объединения, вы можете решить некоторые более сложные требования: python.langchain.com/docs/use_cases/question_answering/…
Я думаю, что мой пример был слишком упрощен. Возможность RunnableParallel возвращать объединенный словарь определенно решает мой пример, но не отвечает на более широкий вопрос о том, как мы можем разрешить эти переменные аналогично тому, как работают PromptTemplates для более сложных требований.