Geração de relatórios estruturados
Relatórios baseados em modelos: resumo executivo, descobertas, evidências e recomendações.
Geração de relatórios estruturados é uma aula grátis de AI Agents no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Agents, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Agents inclui 4 aulas no total.
Dos fatos a um relatório legível
Um agente de pesquisa que produz apenas uma lista de fatos é difícil de usar. Tomadores de decisão precisam de relatórios estruturados: um resumo executivo, uma seção de contexto, principais descobertas, evidências e recomendações.
Esta lição aborda a geração de relatórios profissionais, seção por seção, a partir de fatos verificados.
O modelo do relatório
Defina a estrutura do relatório desde o início. O LLM sintetiza uma seção por vez, mantendo cada seção focada e evitando repetições.
REPORT_SECTIONS = [
'executive_summary',
'background',
'key_findings',
'evidence',
'recommendations',
'sources'
]
SECTION_PROMPTS = {
'executive_summary': 'Write a 2-3 sentence executive summary of the key findings. Business audience.',
'background': 'Provide background context for the research topic (3-5 sentences).',
'key_findings': 'List 3-5 key findings as bullet points, each with one supporting fact.',
'evidence': 'Summarize the evidence for each finding with inline source citations.',
'recommendations': 'Based on the findings, provide 2-4 actionable recommendations.',
'sources': 'List all sources cited in the report, formatted as numbered URLs.'
}
if __name__ == '__main__':
print('Report sections:', REPORT_SECTIONS)
for section in REPORT_SECTIONS:
print(f'{section}: {SECTION_PROMPTS[section]}')
Gerando uma seção por vez
Gerar o relatório inteiro em um único prompt não é confiável — o LLM perde o controle dos fatos e da estrutura. Gere o relatório seção por seção, passando as seções anteriores como contexto.
import openai
client = openai.OpenAI(api_key='YOUR_OPENAI_KEY')
def generate_section(section_name: str, question: str,
facts: list[dict], prior_sections: dict) -> str:
facts_text = '\n'.join(
f'- {f["fact"]} (source: {f["source"]})' for f in facts[:25]
)
prior_text = '\n\n'.join(
f'## {k.replace("_"," ").title()}\n{v}'
for k, v in prior_sections.items()
)
prompt = (
f'Research question: "{question}"\n\n'
f'Verified facts:\n{facts_text}\n\n'
f'Report so far:\n{prior_text}\n\n'
f'Now write the "{section_name}" section.\n'
f'Instructions: {SECTION_PROMPTS[section_name]}'
)
resp = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': prompt}]
)
return resp.choices[0].message.contentConstruindo o relatório de forma iterativa
Percorra todas as seções, passando um contexto acumulado. Cada seção tem conhecimento do que veio antes, o que garante a coerência e evita contradições dentro do relatório.
def build_report(question: str, facts: list[dict]) -> dict:
report = {}
sections_to_generate = [s for s in REPORT_SECTIONS if s != 'sources']
for section in sections_to_generate:
print(f'Generating section: {section}...')
report[section] = generate_section(
section_name=section,
question=question,
facts=facts,
prior_sections={k: v for k, v in report.items()}
)
# Sources section: generate citation list from fact URLs
unique_sources = list(dict.fromkeys(f['source'] for f in facts))
report['sources'] = '\n'.join(
f'{i+1}. {url}' for i, url in enumerate(unique_sources[:20])
)
return reportInserindo citações no texto
Substitua as referências aos fatos nas seções geradas por citações numeradas que apontem para a lista de fontes. Isso torna cada afirmação rastreável.
import re
def inject_citations(section_text: str, facts: list[dict]) -> str:
source_index = {} # url -> int
for i, fact in enumerate(facts):
url = fact['source']
if url not in source_index:
source_index[url] = len(source_index) + 1
annotated = section_text
for fact in facts:
if fact['fact'] in annotated:
num = source_index[fact['source']]
annotated = annotated.replace(
fact['fact'],
f'{fact["fact"]} [{num}]',
1 # replace first occurrence only
)
return annotated
if __name__ == '__main__':
demo_text = 'Revenue grew 12% last quarter. The team also launched two new products.'
demo_facts = [{'fact': 'Revenue grew 12% last quarter', 'source': 'https://example.com/report'}]
print(inject_citations(demo_text, demo_facts))
Formatando como Markdown
Formate as seções do relatório como Markdown. Isso permite converter a saída para HTML, PDF ou exibi-la diretamente em ferramentas como Notion ou Confluence.
def render_markdown(report: dict, title: str) -> str:
section_titles = {
'executive_summary': 'Executive Summary',
'background': 'Background',
'key_findings': 'Key Findings',
'evidence': 'Evidence',
'recommendations': 'Recommendations',
'sources': 'Sources'
}
lines = [f'# {title}', '']
for key in REPORT_SECTIONS:
if key in report:
lines.append(f'## {section_titles[key]}')
lines.append('')
lines.append(report[key])
lines.append('')
return '\n'.join(lines)
# Usage:
# md = render_markdown(report, 'Causes of Inflation in 2024')
# with open('report.md', 'w') as f: f.write(md)Gerando um relatório com links para as fontes
Ao preparar a versão para a web, converta as URLs das fontes em hiperlinks. Adicione também um bloco de metadados com a data de geração do relatório, o número de fontes e a taxa de verificação.
from datetime import date
def render_html_report(report: dict, title: str,
facts: list[dict], question: str) -> str:
meta = (
f'<p><em>Generated: {date.today()} | '
f'Sources: {len(set(f["source"] for f in facts))} | '
f'Research question: {question}</em></p>'
)
html_parts = [f'<h1>{title}</h1>', meta]
section_titles = {
'executive_summary': 'Executive Summary',
'background': 'Background',
'key_findings': 'Key Findings',
'evidence': 'Evidence',
'recommendations': 'Recommendations',
'sources': 'Sources'
}
for key in REPORT_SECTIONS:
if key in report:
content = report[key].replace('\n', '<br>')
html_parts.append(f'<h2>{section_titles[key]}</h2><p>{content}</p>')
return '\n'.join(html_parts)Verificações de qualidade antes da publicação
Execute verificações automatizadas de qualidade antes de entregar o relatório: contagem mínima de palavras por seção, pelo menos N citações, todas as recomendações usando verbos de ação e nenhum texto de espaço reservado, como '[INSERT]'.
def quality_check(report: dict) -> list[str]:
issues = []
for section in ['executive_summary', 'background', 'key_findings']:
word_count = len(report.get(section, '').split())
if word_count < 30:
issues.append(f'{section} too short: {word_count} words (min 30)')
if report.get('sources', '').count('http') < 3:
issues.append('Less than 3 cited sources')
if '[INSERT]' in str(report) or 'TODO' in str(report):
issues.append('Report contains placeholder text')
recs = report.get('recommendations', '')
if recs and not any(verb in recs.lower()
for verb in ['should', 'recommend', 'consider', 'implement']):
issues.append('Recommendations may not be actionable')
return issues
if __name__ == '__main__':
demo_report = {
'executive_summary': 'Too short.',
'background': 'Also short.',
'key_findings': 'Short too.',
'sources': 'http://a.com',
'recommendations': 'Looks fine as is.',
}
for issue in quality_check(demo_report):
print('-', issue)
Resumo executivo: restrições rigorosas
O resumo executivo deve ser autossuficiente: quem ler apenas esta seção deverá entender a principal descoberta e a ação recomendada. Use um prompt rigoroso com um limite de palavras.
def generate_executive_summary(question: str, facts: list[dict],
max_words: int = 80) -> str:
top_facts = '\n'.join(f'- {f["fact"]}' for f in facts[:10])
prompt = (
f'Research question: "{question}"\n\n'
f'Key facts:\n{top_facts}\n\n'
f'Write an executive summary in EXACTLY {max_words} words or fewer.\n'
f'Format: [Main finding]. [Why it matters]. [Recommended action].'
)
resp = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': prompt}]
)
return resp.choices[0].message.contentRelatórios para vários públicos
A mesma pesquisa pode exigir estilos de relatório diferentes para públicos distintos: análise técnica aprofundada para engenheiros, resumo executivo para a liderança e um resumo em linguagem simples para não especialistas. Gere cada variante a partir do mesmo conjunto de fatos.
AUDIENCE_STYLES = {
'executive': 'Brief, strategic. Avoid jargon. Focus on business impact and decisions.',
'technical': 'Detailed, precise. Include methodology, caveats, and data sources.',
'general': 'Plain language. Avoid technical terms. Use analogies where helpful.'
}
def generate_for_audience(facts: list[dict], question: str, audience: str) -> str:
style = AUDIENCE_STYLES.get(audience, AUDIENCE_STYLES['general'])
facts_text = '\n'.join(f'- {f["fact"]}' for f in facts[:20])
prompt = (
f'Synthesize these facts into a report for a {audience} audience.\n'
f'Style guide: {style}\n'
f'Question: "{question}"\n\n'
f'Facts:\n{facts_text}'
)
resp = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': prompt}]
)
return resp.choices[0].message.contentSalvando e criando versões dos relatórios
Salve os relatórios com uma marca de data e hora e o resumo criptográfico da pergunta de pesquisa. Isso permite comparar versões do relatório se a pesquisa for executada novamente com fontes atualizadas.
import hashlib, json, os
from datetime import datetime, timezone
def save_report(report: dict, question: str, output_dir: str = '/tmp/reports'):
os.makedirs(output_dir, exist_ok=True)
q_hash = hashlib.md5(question.encode()).hexdigest()[:8]
timestamp = datetime.now(timezone.utc).strftime('%Y%m%d_%H%M')
filename = f'{output_dir}/report_{q_hash}_{timestamp}.json'
with open(filename, 'w') as f:
json.dump({
'question': question,
'generated': timestamp,
'sections': report
}, f, indent=2)
print(f'Report saved: {filename}')
return filename
if __name__ == '__main__':
import tempfile
demo_dir = tempfile.mkdtemp()
save_report({'executive_summary': 'AI agent adoption grew significantly in 2026.'},
'What are the key AI agent trends in 2026?', output_dir=demo_dir)
Qual seção deve ser sempre autossuficiente na estrutura do relatório?
A estrutura do relatório é projetada para que leitores com pouco tempo possam extrair valor sem ler o documento inteiro. Entender qual seção deve se sustentar sozinha é importante para o projeto do relatório.
Recapitulação da geração de relatórios estruturados
Gere relatórios seção por seção usando um modelo fixo (Resumo executivo → Contexto → Principais descobertas → Evidências → Recomendações → Fontes). Insira citações no texto, execute verificações de qualidade e ofereça estilos para vários públicos a partir do mesmo conjunto de fatos.
Sempre salve os relatórios com marcas de data e hora e resumos criptográficos das perguntas para criar versões.
Perguntas Frequentes
A aula “Geração de relatórios estruturados” é grátis?
Sim — o texto completo de “Geração de relatórios estruturados” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Agents, atualize para CoddyKit PRO. O curso de AI Agents inclui 4 aulas no total.
O que vou aprender em “Geração de relatórios estruturados”?
Relatórios baseados em modelos: resumo executivo, descobertas, evidências e recomendações. Você pratica AI Agents com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar AI Agents?
Nenhuma experiência prévia é necessária. AI Agents no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Geração de relatórios estruturados”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de AI Agents?
Sim. Cada aula de AI Agents inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Projeto de ciclos de pesquisa em várias etapas
- Verificação de fontes e citações
- Geração de relatórios estruturados
- Verificação de fatos e prevenção de alucinações